多重继承允许一个类同时继承多个基类的接口和实现。这是C++的一种强大特性,自语言早期便被广泛使用于实现复杂架构。
问题历史: 多重继承被添加到C++中,作为创建可重复使用的组件和将不同角色合并为一个类的手段(例如,当对象同时是一个线程和一个队列时)。
问题: 多重继承的主要困难是“钻石问题”,对基类成员的访问可能产生歧义,以及构造函数/析构函数调用顺序的不明确性。
解决方案: 为避免上述问题,C++提供了虚拟继承。这保证了公共祖先只会被创建一次,即使多条链路通过层次结构指向它,并确保正确的初始化/销毁顺序。
代码示例:
class A { public: int value; A() : value(1) {} }; class B : virtual public A {}; class C : virtual public A {}; class D : public B, public C {}; int main() { D d; d.value = 10; // OK, 只有一个A return 0; }
关键特性:
如果基类被继承两次(左侧和右侧),对象的内存中会有多少个该类的副本?
默认情况下两个,如果不使用虚拟继承。只有在使用虚拟继承时会有正好一个副本。
在出现歧义时,可以明确指定访问哪个基类的成员吗?
可以,使用限定符:
d.B::value = 5; d.C::value = 6;
在多重继承的情况下,构造函数和析构函数的调用顺序是如何确定的?
构造函数的调用顺序与基类在继承列表中的声明顺序一致(从左到右),然后是派生类本身。对于析构函数则相反。
程序员通过多重继承实现日志和队列系统,却不知道钻石问题。结果导致共同的日志记录器被初始化两次,这在释放资源时导致冲突。
优点:
缺点:
使用虚拟继承来管理共享日志记录器,类成员在构造函数中明确初始化。
优点:
缺点: