多重继承
多重继承描述的是有多个直接基类的类,与单继承一样,公有多重继承表示的都是is-a的关系。而私有多重继承和保护多重继承表示的是has-a的关系。
下面我们看一个例子:
class Base{...};
class BaseA : public Base{...};
class BaseB : public Base{...};
class Abc : public BaseA,public BaseB{...};
···
Abc abc;
Base * base = &abc; //将出现二义性
针对上例,类Abc
多重继承了BaseA
和BaseB
两个类,由于BaseA
和BaseB
都继承了Base
,因此Abc
包含了两个Base
组件,因此在将派生类类对象的地址赋值给基类指针的时候,会出现二义性。abc
包含两个Base
对象,有两个地址可供选择,所以可以使用类型转换来指定对象:
Base * base1 = (BaseA*)&abc;
Base * base2 = (BaseB*)&abc;
这样虽然可以解决上例子带来的二义性,但使得使用基类指针来引用不同的对象(多态性)复杂化。而且实际应用中Abc
类也不需要包含两个Base
对象。因此c++引入了虚基类的概念来解决该情况下的多重继承。
虚基类使得从多个类(他们的基类相同)派生出来的对象只继承一个基类对象。具体的做法如下:
class Base{...};
class BaseA : virtual public Base{...};
class BaseB : public virtual Base{...}; //virtual与public的顺序不做要求,两种写法都是对的
class Abc : public BaseA,public BaseB{...};
这样做可以保证Abc
类对象中只会包含Base
类对象的一个副本。从本质上讲,应该是继承的BaseA
和BaseB
类对象共享了一个Base
对象。这样就可以简单的使用多态。
针对虚基类,在设计的时候需要对其类构造函数采用一种新的方法。例如:
class Base{
int base;
public:
Base(int ba = 0):base(ba){}};
class BaseA : virtual public Base{
int a;
public:
BaseA(int a = 0,int ba = 0): Base(ba),a(a){}
};
class BaseB : virtual public Base{
int b;
public:
BaseC(int b = 0,int ba = 0): Base(ba),b(b) {}
};
class Abc : public BaseA,public BaseB{
int abc;
public:
Abc(int a = 0,int b = 0,int ba = 0; int abc = 0):BaseA(a, ba), BaseB(b, ba), abc(abc){}// flawed
Abc(int a = 0,int b = 0,int ba = 0; int abc = 0):Base(ba), BaseA(a, ba), BaseB(b, ba), abc(abc){}
};
其中,对于:
Abc(int a = 0,int b = 0,int ba = 0; int abc = 0):BaseA(a, ba), BaseB(b, ba), abc(abc){}// flawed
在Base
是虚基类的时候,Abc
类通过BaseA
或BaseB
的构造函数将参数信息间接传递给Base
时将不起作用,c++在基类是虚的时候,禁止将参数信息通过中间类传递给基类。因此上述ba
的信息必不能传递给子对象Base
,然而编译器会使用Base
的默认构造函数,在构造派生类对象之前构造基类对象组件。如果不希望使用默认构造函数来构造虚基类函对象,则需要显式地调用基类构造函数。因此构造函数如下:
Abc(int a = 0,int b = 0,int ba = 0; int abc = 0):Base(ba), BaseA(a, ba), BaseB(b, ba), abc(abc){}
(注:上述代码显式地调用Base
的构造函数,是合法的,但是对于非虚基类,则是非法的。)
如果类有间接虚基类,则除非只使用该虚基类的默认构造函数,否则必须显式地调用该虚基类的某个构造函数。