C++多继承、钻石继承、虚继承

别来无恙 提交于 2020-03-08 07:14:21

      C++的语言特性太多了,一时不用就忘了,本篇记录C++多继承的用法。

一  多继承

      比如有3个类,B派生于类A1, A2, 代码如下

class A1
{
public:
	A1():m_ID(10) {}

public:
	int m_ID;
};

class A2
{
public:
	A2():m_ID(11) {}

public:
	int m_ID;
};

class B : public A1, public A2
{
public:
	B() {}
};

       以上代码父类A1, A2有同名的类成员 m_ID,那么派生类B自然也有m_ID这个成员,那么派生类A该怎么获取m_ID呢,如下代码,直接获取?

      此时编译器报错,“B:m_ID”不明确,不知道调用时哪个类的m_ID成员,正确的写法如下:

二 钻石继承

根据以上代码,在增加一个类A, 让A1, A2都继承于A,那么现在的继承关系如下图:

继承图就像一个菱形,有点像钻石,这种继承方式成为钻石继承,代码如下:

class A
{
public:
	A() :m_Name("Mike") {}

public:
	string m_Name;
};

class A1 : public A
{
public:
	A1():m_ID(10) {}

public:
	int m_ID;
};

class A2 : public A
{
public:
	A2():m_ID(11) {}

public:
	int m_ID;
};

class B : public A1, public A2
{
public:
	B() {}
};

根据代码可知,派生类B, A1, A2都有顶级父类A的成员m_Name, 那么子类B怎么获取m_Name呢?下面这种形式会报错。

 正确的代码如下:

        B b;

	//cout << b.m_Name << endl;
	cout << b.A1::m_Name << endl;
	cout << "A1的m_Name地址" << &(b.A1::m_Name) << endl;

	cout << b.A2::m_Name << endl;
	cout << "A2的m_Name地址" << &(b.A2::m_Name) << endl;

        可以把m_Name的地址输出来,输出如下,可知在类A1, A2中m_Name的地址不同,在A1, A2派生于A时,父类A的成员在子类A1, A2重新分配了没存控件,直接用b.m_Name访问会产生二义性,地址不明确

        其实这种钻石继承还有一个写法,用虚继承来实现。

 

三 虚继承

     让中间父类的继承加上关键字"virtual", 这种成为“虚继承”,代码如下:

class A1 : virtual public A
{
public:
	A1():m_ID(10) {}

public:
	int m_ID;
};

class A2 : virtual public A
{
public:
	A2():m_ID(11) {}

public:
	int m_ID;
};

那么此时用子类B的对象访问m_Name是可以的。

测试结果如下

    

这3个m_Name的地址都一样,说明虚继承,父类成员在派生时,不会重新分内内存空间。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!