Multiple Inheritance - C++
- 多继承比单继承更复杂,引入了歧义的问题,以及虚继承的必要性;
- 虚继承在大小,速度,初始化,复制的复杂性上有不小的代价,当虚基类中没有数据时还是比较合适的;
- 多继承有时也是有用的。典型的场景是:public继承自一些接口类,private继承自哪些实现相关的类。
歧义
class A{
public:
void func();
};
class B{
private:
bool func() const;
};
class C: public A, public B{
... };
C c;
c.func(); // 歧义!
解决冲突的时候就必须
c.A::func();
多继承菱形
class File{
};
class InputFile: public File{
};
class OutputFile: public File{
};
class IOFile: public InputFile, public OutputFile{
};
这样的层级在C++标准库中也存在,例如basic_ios, basic_istream, basic_ostream, basic_iostream。
IOFile的两个父类都继承自File,那么File的属性(比如filename)应该在IOFile中保存一份还是两份呢? 这是取决于应用场景的,就File::filename来讲显然我们希望它只保存一份,但在其他情形下可能需要保存两份数据。 C++还是一贯的采取了自己的风格:都支持!默认是保存两份数据的方式。如果你希望只存储一份,可以用virtual继承:
class File{
};
class InputFile: virtual public File{
};
class OutputFile: virtual public File{
};
class IOFile: public InputFile, public OutputFile{
};
代价:
- 虚继承类的对象会更大一些;
- 虚继承类的成员访问会更慢一些;
- 虚继承类的初始化更反直觉一些。继承层级的最底层(most derived class)负责虚基类的初始化,而且负责整个继承链上所有虚基类的初始化。
对于这些复杂性,建议
- 如果能不使用多继承,就不用他;
- 如果一定要多继承,尽量不在里面放数据,也就避免了虚基类初始化的问题。
接口类
这样一个不包含数据的虚基类和Java或者C#提供的interface有很多共同之处,这样的类在C++中称为接口类,一个Person的接口类是这样的:
class IPerson {
public:
virtual ~IPerson();
virtual std::string name() const = 0;
virtual std::string birthDate() const = 0;
};
内存布局
普通多重继承内存布局
class Base
{
public:
Base(