FP-17 多继承

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::xC::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) */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值