本文首发于个人博客
继承
- 继承,可以让子类拥有父类的所有成员(变量\函数)
默认私有继承
例如下面的代码中,类Cat继承类Animal
1 | class Animal{ |
如下调用的时候,发现设置父类的成员变量,访问父类的函数,会报错。
1 | int main(){ |
修改为public
继承
那是因为C++中默认是私有继承。如果子类想访问父类的函数等,需要public继承,改成如下就可以了。
1 | class Cat : public Animal{ |
c++中没有类似Java中的java.lang.Object 或者ObjectC中的NSObject的基类
对象的内存布局
- 父类的成员变量在前,子类的成员变量在后
上面的代码反汇编
1 | 0x100001160 <+0>: pushq %rbp |
从上面的汇编可以看到age
在height
的地址前面,而且是连续的内存。
多继承
- C++允许一个类可以有多个父类(不建议使用,会增加程序设计复杂度)
如下所示:GoodStudent
同时继承Person
和Student
1 | class Person{ |
对应汇编如下,可知是把父类的成员变量放在了子类中,并且内存是连续的
1 | 0x100000f90 <+0>: pushq %rbp |
多个父类同样的函数
1 | class Person{ |
子类调用的时候需要区分命名空间
1 | stu.Person::run(); //调用Person的run() |
菱形继承
如果存在类A,同时类B和类C都继承A,有类D继承B和C。则称为菱形继承
一般在开发中,不会使用菱形继承。
- 最底下子类从基类继承的成员变量冗余、重复
- 最底下子类无法访问基类的成员,有二义性
例如如下的代码中,就是菱形继承的例子
1 | class Person{ |
在X86架构下,一个GoodStudent对象占用内存20字节,是因为,Student和Work都从Person继承了age,那么GoodStudent中就有2个age了。同时加上score,height, salary就是5个成员变量。
1 | GoodStudent stu; |
虚继承
为了解决菱形继承的问题,我们可以使用虚继承。
如下代码 Person类被称为虚基类
1 | class Person{ |
这样一个GoodStudent对象里面只有一个age成员变量。当然这样做增加了虚函数表。这里不做展开。
成员访问权限
- 成员访问权限、继承方式有3种
- public:公共的,任何地方都可以访问(struct默认)
- protected:子类内部、当前类内部可以访问
- private:私有的,只有当前类内部可以访问(class默认)
- 子类内部访问父类成员的权限,是以下2项中权限最小的那个
- 成员本身的访问权限
- 上一级父类的继承方式
- 开发中用的最多的继承方式是public,这样能保留父类原来的成员访问权限
- 访问权限不影响对象的内存布局
初始化列表
- 一种便捷的初始化成员变量的方式
- 只能用在构造函数中
- 初始化顺序只跟成员变量的声明顺序有关
下面两种写法是等价的
1 | class Person{ |
初始化列表与默认参数配合使用
例如下面的代码
1 | class Person{ |
使用的时候如下三种都可以
1 | Person person1; |