Diamond-shaped inheritance of inheritance in C++ [super detailed graphic + code]

 

 


Preface

We said in the previous article that everything in the world has an inheritance system. More or less subclasses inherit certain characteristics of the parent class, but most of them are unidirectional inheritance, but there are some exceptions that are multiple inheritance, such as:

We can see from the picture that amphibians have inherited part of the characteristics of aquatic animals and some of the characteristics of terrestrial animals. Will our code also have this kind of multiple inheritance? Get up and take a look.


Tip: The following is the content of this article, the following cases are for reference

1. What is multiple inheritance?

1. Single inheritance

  Let's take a look at a diagram to understand single inheritance first, and then see the difference

In other words, when a subclass has only one direct parent class, the inheritance relationship is called single inheritance.

 

2. Multiple inheritance

We call this inheritance for multiple inheritance when a sub-class has two or more direct parent

Let's take a look at the code to see what problems exist in multiple inheritance.

//基类A
class A 
{
public:
    A() :m_data(1)
    {
    }
    ~A(){}

public:
    int m_data;      //同名变量
   
};
//基类B
class B
{
public:
    B() :m_data(1)
    {
    }
    ~B(){}

public:
    int m_data;      //同名变量
    
};

class C  : public A, public B
{

};

int main()
{
    C Data;
   //Data.m_data  = 10;   //错误, 提示指向不明确  不能够分辨m_data到底是谁的
   //只有通过域成员运算符给其明确指出才可以访问,
    Data.A::m_data = 5; 
    Data.B::m_data =10;
    
    std::cout << Data.A::m_data << "   " << Data.B::m_data << std::endl;

    return 0;
}

 

By the above code we obviously see out , ambiguity problems of multiple inheritance system . Means that if there is a data member with the same name, then it cannot be read directly by the variable name, and it needs to be distinguished by the domain (::) member operator

It's like a person says to send something to the teacher. With so many teachers, you can't be sure which teacher he is referring to. You must name it by name so that we can distinguish. A truth

Second, diamond inheritance

Let’s draw a picture first to understand what is called diamond inheritance

 

We call this type of inheritance diamond inheritance.

So what kind of problems will arise with this inheritance system? Let's take a look at it in detail through the following code.

//  菱形继承 菱形继承是多继承的一种特殊情况。
//菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。


class A
{
public:
	int m_a = 1;
};
class B :public A
{
public:
	int m_b = 2;
};
class C :public A
{
public:
	int m_c = 3;
};
class D :public B, public C
{
public:
	int m_d = 4;
};
void main()
{
	D d;
	d.m_d = 40;
	d.m_c = 30;
	d.m_b = 20;
	//.m_a = 10;//  二义性
	// 不能够访问  因为B 和C分别继承了A的m_a
	//但是D 继承了B和C的m_a 所以D不能够分辨m_a到底是谁的
	d.B::m_a = 100;
	d.C::m_a = 200;
	// 这样的话 就造成了m_a 有两个空间  一个B的100  一个C的200
}

Based on the above situation, it is not difficult to see that data ambiguity also exists in diamond inheritance. The ambiguity here is caused by indirectly having the same base class . In addition to the ambiguity of this kind of diamond inheritance , there will be data redundancy and waste of memory space .

What is waste of space and data redundancy, let's draw a picture to show it.

So how to solve this problem,

1. The introduction of virtual base classes

The virtual base class is introduced in C++ , whose function is  to retain only one member of the base class when indirectly inheriting the common base class.

Let's take a look at the code

class A
{
public:
	int m_a = 1;
};
class B :virtual public A
{
public:
	int m_b = 2;
};
class C :virtual public A
{
public:
	int m_c = 3;
};
class D :public B, public C
{
public:
	int m_d = 4;
};
void main()
{
	D d;
	d.m_d = 40;
	d.m_c = 30;
	d.m_b = 20;
	d.m_a = 100;//  让B C虚拟继承 A 加关键字virtual
}

We can see that the problem of ambiguity and data redundancy is solved very well, so how does it do it specifically,

2. The introduction of virtual base table

Here is a table pointed to by the two pointers of B and C. These two pointers are called virtual base table pointers, and these two tables are called virtual base tables. The offset stored in the virtual base table. A can be found by the offset.

Specifically, we draw a picture

The BC here is like two people in two different places, but they have to go to the place A, and save the address of A, then you can use the map to navigate, but because the two people are in different places, so go to A The distance will definitely be different, that is, the offset of A will definitely be different ( it will be easier to understand this way).

 

 

to sum up

Many people say that C++ syntax is complicated, but in fact, multiple inheritance is a manifestation. With multiple inheritance, there is diamond inheritance, and with diamond inheritance, there is diamond virtual inheritance, and the underlying implementation is very complicated. Therefore, it is generally not recommended to design multiple inheritance, and must not design diamond inheritance. Otherwise, there will be problems in complexity and the virtual inheritance of diamond-shaped inheritance also brings performance loss (because more addresses are opened to store the offset) .

 

Thank you for reading, and please correct me if there are any errors.

Guess you like

Origin blog.csdn.net/qq_45615577/article/details/115345490