Lecture 17 多继承
多继承的需要性
对于下面的两个类A和B:
class A
{ int m;
public:
void fa();
};
class B
{ int n;
public:
void fb();
};
如何定义一个类C,它包含A和B的所有成员,另外还拥有新的数据成员r和成员函数fc?
用单继承实现:
class C: public A
{ int n,r; //把B类中的n复制过来
public:
void fb(); //把B类中的fb复制过来
void fc();
};
或:
class C: public B
{ int m,r; //把A类中的m复制过来
public:
void fa(); //把A类中的fa复制过来
void fc();
};
不足之处:
-
概念混乱:导致A和B之间增加了层次关系。
-
易造成不一致:A中的m、fa(或B中的n、fb)与C中的m、fa(或n、fb)
-
不能完全实现子类型。
用成员对象实现:
class C
{ A a;
B b;
int r;
public:
void fa() { a.fa(); }
void fb() { b.fb(); }
void fc();
};
不足之处:
- 不能实现子类型:程序中的A或B的对象不能用C的对象去替代,…。
用多继承实现:
class C: public A, public B
{ int r;
public:
void fc();
};
多继承的类定义
多继承是指派生类可以有一个以上的直接基类。多继承的派生类定义格式为:
class <派生类名>: [<继承方式>] <基类名1>,
[<继承方式>] <基类名2>, …
{ <成员说明表>
};
-
继承方式及访问控制的规定同单继承。
-
派生类拥有所有基类的所有成员。
-
基类的声明次序决定:
- 对基类构造函数/析构函数的调用次序
- 对基类数据成员的存储安排。
class A
{ int m;
public:
void fa();
};
class B
{ int n;
public:
void fb();
};
class C: public A, public B
{ int r;
public:
void fc();
};
......
C c;
c.fa(); //OK
c.fb(); //OK
c.fc(); //OK
构造函数的执行次序是:A()、B()、C()
(A()和B()实际是在C()的成员初始化表中调用。)
可以把以public继承方式定义的多继承派生类的对象的地址赋给任何一个基类的指针,这时将会自动进行地址调整。
多继承中的名冲突问题
class A
{ ......
public:
void f();
void g();
};
class B
{ ......
public:
void f();
void h();
};
class C: public A, public B
{ ......
public:
void func()
{ f(); //Error,是A的f,还是B的f?
}
};
......
C c;
c.f(); //Error,是A的f,还是B的f?
解决名冲突的办法是:基类名受限
class C: public A, public B
{ ......
public:
void func()
{ A::f(); //OK,调用A的f。
B::f(); //OK,调用B的f。
}
};
......
C c;
c.A::f(); //OK,调用A的f。
c.B::f(); //OK,调用B的f。
重复继承问题--虚基类
下面的类D从类A继承两次,称为重复继承:
class A
{ int x;
......
};
class B: public A { ... };
class C: public A { ... };
class D: public B, public C { ... };
D d;
上面D类的对象d将包含两个x:B::x
和C::x
如果要求类D中只有一个x,则应把A定义为B和C的虚基类:
class B: virtual public A {...};
class C: virtual public A {...};
class D: public B, public C {...};
D d;
这样,D类的对象d就只有一个x了。
虚基类构造函数的调用
对于间接包含虚基类的类:
-
虚基类的构造函数由该类的构造函数直接调用。(虚基类的构造函数由最新派生出的类的构造函数调用)
-
虚基类的构造函数优先非虚基类的构造函数执行。
class A
{ int x;
public:
A(int i) { x = i; }
};
class B: virtual public A
{ int y;
public:
B(int i): A(1) { y = i; }
};
class C: virtual public A
{ int z;
public:
C(int i): A(2) { z = i; }
};
class D: public B, public C
{ int m;
public:
D(int i, int j, int k): B(i), C(j), A(3) { m = k; }
};
class E: public D
{ int n;
public:
E(int i, int j, int k, int l): D(i,j,k), A(4) { n = l; }
};
......
D d(1,2,3); //这里,A的构造函数由D调用,d.x初始化为3。
/*调用的构造函数及它们的执行次序是:
A(3)、B(1)、C(2)、D(1,2,3)
*/
E e(1,2,3,4); //这里, A的构造函数由E调用,e.x初始化为4。
/*调用的构造函数及它们的执行次序是:
A(4)、B(1)、C(2)、D(1,2,3)、E(1,2,3,4) */