高级程序设计

19 - 多继承

2020-04-09 14:00 CST
2020-04-11 14:52 CST
CC BY-NC 4.0

假设类C需要有A、B的成员,并拥有自己的内容:

单继承实现的问题:

  • 概念混乱,派生类之间增加了层次关系
  • 容易造成不一致

用聚集(成员对象)实现的问题

  • 不能实现子类型,程序中的对象不能用聚集替代

多继承

多继承是指派生类可以有一个以上的直接基类。

继承方式及访问控制的规定与单继承相同,派生类拥有基类的所有成员。

基类的声明次序决定:

  • 对基类构造函数/析构函数的调用次序;
  • 对基类数据成员的存储安排。

可以将以public继承方式定义的多继承派生对象的地址赋值给任何一个基类的指针,此时会自动地对指针的地址进行调整。

多继承中的名冲突问题

使用基类名受限解决名冲突问题:

class A { public: void f(); };
class B { public: void f(); };
class C : public A, public B {
  public:
    void foo() {
      f(); // error
      A::f(); // OK
    }
}

重复继承问题与虚基类

一个类可能继承基类多次,称为重复继承:

class A { public: int x; };
class B : public A;
class C : public A;
class D : public B, public C { ... };

此时D类的对象将会包含两个x

解决方案:将A定义为B和C的虚基类,即:

class B : virtual public A;
class C : virtual public A;
class D : public B, public C { ... };

虚基类构造函数的调用:对于间接包含虚基类的类,虚基类的构造函数由该类的构造函数直接调用(由最新派生出的类的构造函数调用);虚基类的构造函数优先于非虚基类的构造函数执行。

C++中的实现:

  • 非虚基类:按顺序存储基类内容,最后存储派生类内容;
  • 虚基类:非虚基类的内容按顺序存储;将虚基类的内容移动到最后,在原来存储成员的位置添加一个偏移量指针(在虚基类表vtable中存放偏移量)。