(36.2)多重继承之虚基类

1.虚基类

  • C++提供虚基类(virtual base class) 的机制, 使得在继承间接共同基类时只保留一份成员。eg:只保留基类A的一份副本
    在这里插入图片描述
    由A派生出B1和B2,由于C1和C2都保留了基类A的所有的成员,那么D类继承C1和C2时,会继承2次,此时会产生二义性问题

  • 虚基类的定义
    (1)虚基类是在派生类定义时, 指定继承方式时声明的。
    (2)需要注意, 为了保证虚基类在派生类中只继承一次, 应当在该基类的所有直接派生类中声明为虚基类。
    否则仍然会出现对基类的多次继承。
    声明虚基类的一般形式为:

class 派生类名: virtual 访问标号 虚基类名,... 
{ //类体
	成员列表
};
  • eg:
#include <iostream>
using namespace std;
class A// 声明为基类A
{
	public://外部接口
		A(int n)//A类的构造函数
		{
			nv=n;
			cout<<"Member of A"<<endl;
		}
		void fun()
		{
			cout<<"fun of A"<<endl;
		}
	private:
		int nv;//私有成员
};

class B1:virtual public A//声明A为虚基类,派生出B1
{
	public:
		B1(int a):A(a)//B1类的构造函数
		{
			cout<<"Member of B1"<<endl;
		}
		private:
			int nv1;
};

class B2:virtual public A//声明A为虚基类
{
	public:
		//B2类的构造函数
		B2(int a):A(a)
		{
			cout<<"Member of B2"<<endl;
		}
	private:
		int nv2;
};

//这里继承A类的成员继承了2回,但是由于B1和B2都将A声明为虚基类,所以C继承A类的成员只会继承1class C:public B1,public B2
{
	public:
		// 派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用
		C(int a):A(a),B1(a),B2(a)
		{
			cout<<"Member of C"<<endl;
		}
		void fund()
		{
			cout<<"fun of C"<<endl;
		}
	private:
		int nvd;
};

int main()
{
	C c1(1);//调用构造函数的顺序是:A,B1,B2,C的构造函数
	c1.fund();
	c1.fun();//不会产生二义性

	return 0;
}


运行结果:
Member of A
Member of B1
Member of B2
Member of C
fun of C
fun of A

2.虚基类的初始化

  • 如果在虚基类中定义了带参数的构造函数, 而且没有定义默认构造函数 (就是不带参数的构造函数), 则在其所有派生类(包括直接派生和间接派生)中, 都要通过构造函数的初始化表对虚基类进行初始化。
    例如 :
class A 
{ 
	public: 
		A(int) {} 
}; //定义基类

class B : virtual public A 
{ 
	public: B(int a):A(a) {} 
};//对基类A初始化

class C : virtual public A 
{ 
	public: C(int a):A(a) {} 
};//对基类A初始化
c
lass D : public B,public C
{ 
	public: D(int a):A(a),B(a),C(a) {} 
};

不仅对B和C进行初始化,还要对A进行初始化
  • 在最后的派生类中不仅要负责对其直接基类进行初始化, 还要负责对虚基类初始化

  • 关于虚基类的说明:
    (1) 一个类可以在一个类族中既被用作虚基类, 也被用作非虚基类。
    (2) 派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用; 如果未列出, 则表示使用该虚基类的默认构造函数。
    (3) 在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时, 虚基类的构造函数先于非虚基类的构造函数执行。

  • eg:

#include <iostream>
using namespace std;
enum Color {Red,Yellow,Green,White};//颜色枚举类型
class Circle//圆类Circle的定义
{
	float radius;//私有成员
	public:
		Circle(float r)
		{
			radius=r;
			cout<<"Circle initialized!"<<endl;
		}
		~Circle()
		{
			cout<<"Circle destroyed!"<<endl;
		}
		float Area()
		{
			return 3.1415926*radius*radius;
		}
};


class Table//桌子类Table的定义
{
	float height;
	public:
		Table(float h)
		{
			height=h;
			cout<<"Table initialized"<<endl;
		}
		~Table()
		{
			cout<<"Table destroyed!"<<endl;
		}
		float Height()
		{
			return height;
		}
};

class RoundTabe:public Table,public Circle//圆桌类的定义
{
	Color color;
	public:
		RoundTable(float h,float r,Color C);//派生类的构造函数要考虑:基类的数据成员+派生的数据成员
		int GetColor()
		{
			return color;
		}
		~RoundTabe()
		{
			cout<<"RoundTable destroyed!"<<endl;
		}
};
RoundTable::RoundTable(float h,float r,Color c):Table(h),Circle(r)//圆桌构造函数的定义
{
	color=c;
	cout<<"RoundTable initialized!"<<endl;
}

int main()
{
	RoundTable cir_table(15.0,2.0,Yellow);//注意构造函数的调用顺序
	cout<<"The table properties are:"<<endl;
	cout<<"Height="<<cir_table.Height()<<endl;//调用Table类的成员函数
	cout<<"Area="<<cir_table.Area()<<endl; //调用circle类的成员函数
	cout<<"Color="<<cir_table.GetColor()<<endl; //调用RoundTable类的成员函数
	return 0;
}

构造函数与析构函数的调用顺序相反
结果:
Table initialized!
Circle initialized!
RoundTable initialized!
The table properties are:
Height=15
Area=12.5664
Color=1
RoundTable destroyed!
Circle destroyed!
Table destroyed!

发布了556 篇原创文章 · 获赞 140 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/u011436427/article/details/104160852