1. 多继承的名字冲突问题
多继承:一个类可以同时继承多个类,但是多继承很容易产生同名冲突(函数、变量)。
class A { public: int m_a; int m_b; }; class B { public: int m_a; int m_b; }; class CCCC : public A, public B {}; void test01() { CCCC c; c.A::m_a; c.B::m_a; }
对于上述情况,如果由于多继承出现的名字冲突问题,需要通过指定类作用域的方式加以区分。
2. 多继承的优点
多继承并不是一无是处,也会有自己的一些使用场景,通过多继承可以复用多个类的代码和数据。在不影响类继承的情况下,赋予子类一些功能。比如:想要实现,统计 Cat 和 Dog 的对象创建个数:
class ObjectCount { public: ObjectCount() { ++m_cnt; cout << "当前 Animal 对象个数:" << m_cnt << endl; } ~ObjectCount() { --m_cnt; cout << "当前 Animal 对象个数:" << m_cnt << endl; } public: static int m_cnt; }; int ObjectCount::m_cnt = 0; class Animal { public: void walk() { cout << "走路" << endl; } public: int m_type; // 动物的品种 }; // Cat 类只需要多继承一个 ObjectCount 类,就可以自动实现对象创建的个数统计 // Cat 类创建对象时,会调用父类的构造函数 ObjectCount ,从而对对象个数进行累加 // Cat 类对象销毁时,会调用父类的析构函数 ObjectCount ,从而减少对象的个数 class Cat : public Animal, public ObjectCount {}; class Dog : public Animal, public ObjectCount {}; void test02() { Cat c1, c2, c3; Dog d1, d2; }
3. 菱形继承问题
在 C++ 中的多继承过程中,还可能出现菱形继承问题(钻石继承),如下代码所示:
class BBB { public: int m_bbb; }; // AAA 类有两个成员变量: m_bbb、m_aaa class AAA : public BBB { public: int m_aaa; }; // CCC 类有两个成员变量: m_bbb、m_ccc class CCC : public BBB { public: int m_ccc; }; // DDD 类有 2 个 m_bbb, m_aaa、m_ccc、m_ddd class DDD : public AAA, public CCC { public: int m_ddd; }; // 问题:1. 二义性(对象中出现了两个同名成员) 2. 菱形继承顶层基类的数据成员的重复、冗余。 void test03() { DDD d; d.AAA::m_bbb; d.CCC::m_bbb; }
4. 虚继承机制
虚继承解决的是菱形继承中,最顶层基类的数据冗余、二义性问题。
把最顶层的基类当做虚基类,告诉编译期它的数据是共享的,而不是随着继承层增多,数据冗余增多。
虚继承必须在运行阶段完成,编译阶段无法完成。
不建议大家使用多继承(菱形继承),并不是不能使用。
class BBB { public: int m_bbb; }; // AAA 类虚继承 BBB 类,BBB 类就叫做虚基类 class AAA : virtual public BBB { public: int m_aaa; }; // CCC 类虚继承 BBB 类 class CCC : virtual public BBB { public: int m_ccc; }; // DDD 类有 2 个 m_bbb, m_aaa、m_ccc、m_ddd class DDD : public AAA, public CCC { public: int m_ddd; }; void test03() { DDD d; d.m_bbb; d.AAA::m_bbb; d.CCC::m_bbb; }
虚基类的初始化问题
普通继承结构中,本类负责调用直接父类的构造函数初始化
虚继承结构中,每一个虚基类的子类,都需要负责虚基类的初始化,这样才能保证虚基类能够被初始化、并且只有一次被初始化。
默认情况下会调用虚基类的默认构造,当其不存在默认构造函数时,每一个虚基类的子类都需要使用初始化列表初始化虚基类
class BBB { public: BBB(int) { cout << "BBB 构造函数" << endl; } ~BBB() { cout << "BBB 析构函数" << endl; } public: int m_bbb; }; // AAA 类虚继承 BBB 类,BBB 类就叫做虚基类 class AAA : virtual public BBB { public: AAA() : BBB(0) { cout << "AAA 构造函数" << endl; } ~AAA() { cout << "AAA 析构函数" << endl; } public: int m_aaa; }; // CCC 类虚继承 BBB 类 class CCC : virtual public BBB { public: CCC() : BBB(0) { cout << "CCC 构造函数" << endl; } ~CCC() { cout << "CCC 析构函数" << endl; } public: int m_ccc; }; // DDD 类创建对象的时候,直接调用了 BBB 类的构造函数 class DDD : public AAA, public CCC { public: DDD() : BBB(0) { cout << "DDD 构造函数" << endl; } ~DDD() { cout << "DDD 析构函数" << endl; } public: int m_ddd; }; void test04() { DDD d; }