Inheritance
Inheritance is to take the existing class, clone it, and then make additions and modifications to the clone.
Inheritance 实际上是复用接口,基于已有的类生成。旧类称为父类(基类),新类称为子类(派生类)。
与 Composition 的区别:Composition 生成的新类中含有旧类的对象作为成员,而 Inheritance 生成的新类含有旧类的接口、成员。
新类和旧类的关系:New class "is a" (special) old class。子类具有和父类相同的本质,具有更多的属性和接口(服务)。因此子类是父类的超集。
语法
声明
class B{
public:
B(int v1, int v2);
private:
int data1, data2;
};
class A: public B{
public:
A(int v1, int v2, int v3);
private:
int data3;
};
构造函数
B::B(int v1, int v2):
data1(v1), data2(v2){}
A::A(int v1, int v2, int v3):
B(v1, v2), data3(v3){}
注意事项:
- 父类对象一定是最先初始化的
- 如果没有显式地构造父类对象
- 则会调用默认构造函数
- 析构函数仍然按照与构造函数相反的顺序被调用,即父类的析构函数更晚调用
初始化列表的三种内容
- 成员变量
- 父类构造函数
- 代理构造
非公开的继承
class B: protected A{
...
};
class B: private A{//default
...
};
如果定义 protected 继承,只有子类及其派生类可以调用父类方法,外部是不可以的。
如果定义 private 继承,只有子类本身可以调用父类方法。
C++ 语法上的 private 继承不被认为是 OOP 语义上的继承,因为外部不能调用其父类的任何方法,不能认为这是父类的一个派生类。实际上这等于 composition。
举例
Database of Multimedia Entertainment (DoME)
存储 CD 和 DVD 的数据
CD 的数据:1. 专辑的名称 2. 歌手的名称 3. 歌曲数 4. 总时长 5. got_it 标记是否在库中 6. 其他描述
DVD 的数据:1. 电影的名称 2. 导演的名称 3. 总时长 4. got_it 标记是否在库中 5. 其他描述
Database 类:存放 CD、DVD 的两个 vector
Code duplication:不易于维护和改造
设计父类 Item,保存 CD 4. 5. 6. / DVD 3. 4. 5.,CD和 DVD 作为子类。
继承的优点
-
代码复用
不同的类可以继承自同一父类,同类的数据和方法在父类中完成
-
可扩展性
代码不经修改就能接受新的类型
可维护性:简单修改后能接受新的类型
-
更方便的维护
父类与子类数据的关系
父类的私有成员变量
父类的私有成员变量,在子类中仍然会存在,但使用子类的方法不可访问。
想要访问,只能通过父类的方法。
实践可以发现,父类对象的数据在子类对象的最前面。所以外部指针指向子类对象时,也可以认为其指向了一个父类对象。
公共成员函数
All objects of a particular class can receive the same messages. -- Alan Key
公共成员函数实际上就是类的接口。
子类继承了父类所有的 public 函数,所以能做父类能做的所有操作。
保护(protected)成员
父类的 protected 成员是留给子类的遗产,子类可以访问但外界不能访问。
静态(static)成员
访问属性仍然取决于 public/protected,但是修改之后会影响父类及其所有派生类。
Name Hiding
如果子类中没有重载父类函数,可以直接调用;
如果子类重载了父类函数,那么父类所有同名的重载均会失效,称为 Name hiding。
在下一讲会介绍,使用关键字 virtual
可以解决这一问题。