51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

C++ 多继承中的虚继承机制

  1. 多继承的名字冲突问题 {#title-0} ========================

多继承:一个类可以同时继承多个类,但是多继承很容易产生同名冲突(函数、变量)。

class A 
{
public:
	int m_a;
	int m_b;
};
class B 
{
public:
	int m_a;
	int m_b;
};
class CCCC : public A, public B {};
void test01()
{
	CCCC c;
	c.A::m_a;
	c.B::m_a;
}

对于上述情况,如果由于多继承出现的名字冲突问题,需要通过指定类作用域的方式加以区分。

  1. 多继承的优点 {#title-1} ====================

多继承并不是一无是处,也会有自己的一些使用场景,通过多继承可以复用多个类的代码和数据。在不影响类继承的情况下,赋予子类一些功能。比如:想要实现,统计 Cat 和 Dog 的对象创建个数:

class ObjectCount
{
public:
	ObjectCount()
	{
		++m_cnt;
		cout << "当前 Animal 对象个数:" << m_cnt << endl;
	}
~ObjectCount()
{
	--m_cnt;
	cout &lt;&lt; &quot;当前 Animal 对象个数:&quot; &lt;&lt; m_cnt &lt;&lt; endl;
}

public: static int m_cnt; };

int ObjectCount::m_cnt = 0;

class Animal { public: void walk() { cout << "走路" << endl; } public: int m_type; // 动物的品种 };

// Cat 类只需要多继承一个 ObjectCount 类,就可以自动实现对象创建的个数统计 // Cat 类创建对象时,会调用父类的构造函数 ObjectCount ,从而对对象个数进行累加 // Cat 类对象销毁时,会调用父类的析构函数 ObjectCount ,从而减少对象的个数 class Cat : public Animal, public ObjectCount {}; class Dog : public Animal, public ObjectCount {};

void test02() { Cat c1, c2, c3; Dog d1, d2; }

  1. 菱形继承问题 {#title-2} ====================

在 C++ 中的多继承过程中,还可能出现菱形继承问题(钻石继承),如下代码所示:

class BBB
{
public:
	int m_bbb;
};

// AAA 类有两个成员变量: m_bbb、m_aaa class AAA : public BBB { public: int m_aaa; };

// CCC 类有两个成员变量: m_bbb、m_ccc class CCC : public BBB { public: int m_ccc; };

// DDD 类有 2 个 m_bbb, m_aaa、m_ccc、m_ddd class DDD : public AAA, public CCC { public: int m_ddd; };

// 问题:1. 二义性(对象中出现了两个同名成员) 2. 菱形继承顶层基类的数据成员的重复、冗余。 void test03() { DDD d; d.AAA::m_bbb; d.CCC::m_bbb; }

  1. 虚继承机制 {#title-3} ===================

虚继承解决的是菱形继承中,最顶层基类的数据冗余、二义性问题。
把最顶层的基类当做虚基类,告诉编译期它的数据是共享的,而不是随着继承层增多,数据冗余增多。
虚继承必须在运行阶段完成,编译阶段无法完成。
不建议大家使用多继承(菱形继承),并不是不能使用。

class BBB
{
public:
	int m_bbb;
};

// AAA 类虚继承 BBB 类,BBB 类就叫做虚基类 class AAA : virtual public BBB { public: int m_aaa; };

// CCC 类虚继承 BBB 类 class CCC : virtual public BBB { public: int m_ccc; };

// DDD 类有 2 个 m_bbb, m_aaa、m_ccc、m_ddd class DDD : public AAA, public CCC { public: int m_ddd; };

void test03() { DDD d; d.m_bbb; d.AAA::m_bbb; d.CCC::m_bbb; }

虚基类的初始化问题
普通继承结构中,本类负责调用直接父类的构造函数初始化
虚继承结构中,每一个虚基类的子类,都需要负责虚基类的初始化,这样才能保证虚基类能够被初始化、并且只有一次被初始化。
默认情况下会调用虚基类的默认构造,当其不存在默认构造函数时,每一个虚基类的子类都需要使用初始化列表初始化虚基类

class BBB
{
public:
	BBB(int)
	{
		cout << "BBB 构造函数" << endl;
	}
~BBB()
{
	cout &lt;&lt; &quot;BBB 析构函数&quot; &lt;&lt; endl;
}

public: int m_bbb; };

// AAA 类虚继承 BBB 类,BBB 类就叫做虚基类 class AAA : virtual public BBB { public: AAA() : BBB(0) { cout << "AAA 构造函数" << endl; }

~AAA()
{
	cout &lt;&lt; &quot;AAA 析构函数&quot; &lt;&lt; endl;
}

public: int m_aaa; };

// CCC 类虚继承 BBB 类 class CCC : virtual public BBB { public: CCC() : BBB(0) { cout << "CCC 构造函数" << endl; }

~CCC()
{
	cout &lt;&lt; &quot;CCC 析构函数&quot; &lt;&lt; endl;
}

public: int m_ccc; };

// DDD 类创建对象的时候,直接调用了 BBB 类的构造函数 class DDD : public AAA, public CCC { public: DDD() : BBB(0) { cout << "DDD 构造函数" << endl; }

~DDD()
{
	cout &lt;&lt; &quot;DDD 析构函数&quot; &lt;&lt; endl;
}

public: int m_ddd; };

void test04() { DDD d; }

赞(3)
未经允许不得转载:工具盒子 » C++ 多继承中的虚继承机制