[C ++]-virtual base class

1. The concept of virtual base class

Earlier, we learned that an abstract class is a class with pure virtual functions. And what is the virtual base class?
First of all, we can be clear that vietual can be modified in two places. The first is to modify the member method is a virtual function, and the second is to modify the inheritance method is virtual inheritance. Virtual inherited class is called virtual base class

Therefore, we can give the definition of the virtual base class: the virtual inherited class is called the virtual base class vbptr and vbtable.
For example, the following code, class A is a virtual base class

class A
{
public:
private:
	int ma;
};
class B:virtual public A
{
public:
private:
	int mb;
};

In this, we draw, the memory structure diagram of the class is as follows.
Insert picture description here
According to the memory structure of virtual functions drawn before, we first draw the memory structure when there is no virtual base class, and then make adjustments to get the memory map when there is a base class.
What does vbptr point to? As shown below:
Insert picture description here

2. The coexistence of virtual base classes and virtual functions

The above code is just a simple virtual base class. If we add a virtual function to the virtual base class, what will happen to the memory structure? The
code is as follows:

class A
{
public:
	virtual void func() { cout << "call A::func" << endl; }
private:
	int ma;
};
class B :virtual public A
{
public:
	virtual void func() { cout << "call B::func" << endl; }
private:
	int mb;
};
int main()
{
	A* p = new B();
	p->func();
	delete p;
	return 0;
}

The results are as follows:
Insert picture description here
Why did the above error occur? Let's analyze it.
First, we still draw the corresponding memory structure diagram as follows:
Insert picture description here
Next, think about where the pointer p refers to?
The base class pointer points to the derived class object, and it always points to the starting position of part of the data of the derived class base class as shown in the following figure: The
Insert picture description here
reason for the error is that the error occurred during memory recycling. As shown below:
Insert picture description here
when developing memory, it was developed from 013855D0, which is vbptr, but when reclaiming memory, it was started in the virtual base class, and there was a problem of memory leak.

Improvement method: Open an object on the stack in the main function, without destructuring, the object will reclaim memory by itself, the following code:

int main()
{
	B b;
	A* p = &b;
	cout << "main p:" << p << endl;
	p->func();
	return 0;
}

The results are as follows:
Insert picture description here

3. The problem of diamond inheritance solved by virtual base class

Regarding diamond inheritance, there are indirect inheritance and other problematic inheritance methods as shown in the following figure:
Insert picture description here
This has design problems, and the derived class has multiple copies of the indirect base class data. For example, ma in the picture. Corresponding to a specific class, if ma is a name attribute, then there will be two names in the D object to raise objections.
For the diamond inheritance shown above, the code implementation is as follows:

class A
{
public:
	A(int data) :ma(data) { cout << "A()" << endl;}
	~A() { cout << "~A()" << endl; }
protected:
	int ma;
};
class B :public A
{
public:
	B(int data) :A(data),mb(data) { cout << "B()" << endl; }
	~B() { cout << "~B()" << endl; }
protected:
	int mb;
};
class C : public A
{
public:
	C(int data) :A(data), mc(data) { cout << "C()" << endl; }
	~C() { cout << "~C()" << endl; }
protected:
	int mc;
};
class D :public B,public C
{
public:
	}
	~D() { cout << "~D()" << endl; }
protected:
	int md;
};
int main()
{
	D d(10);
	return 0;
}

The results are as follows:
Insert picture description here
From this, we can draw the memory layout of D as follows:
Insert picture description here
we can clearly see the problem of multiple copies of indirect base classes. Therefore, we can use the virtual base class to solve the problem
Insert picture description here
so that we can access the data of ma through the offset indicated by the virtual pointer.
Here, we must pay attention to that, in class D, we must initialize class A, otherwise, there will be an error that the default constructor A cannot be found. The code is implemented as follows:

class A
{
public:
	A(int data) :ma(data) { cout << "A()" << endl;}
	~A() { cout << "~A()" << endl; }
protected:
	int ma;
};
class B :virtual public A
{
public:
	B(int data) :A(data),mb(data) { cout << "B()" << endl; }
	~B() { cout << "~B()" << endl; }
protected:
	int mb;
};
class C : virtual public A
{
public:
	C(int data) :A(data), mc(data) { cout << "C()" << endl; }
	~C() { cout << "~C()" << endl; }
protected:
	int mc;
};
class D :public B,public C
{
public:
	D(int data) :A(data),B(data), C(data),md(data) { cout << "B()" << endl; }
	D(int data) : B(data), C(data), md(data) { cout << "B()" << endl; }
protected:
	int md;
};
int main()
{
	D d(10);
	return 0;
}

The results of the operation are as follows:
Insert picture description here
the problem is solved by the virtual base class.

Published 98 original articles · won praise 9 · views 3662

Guess you like

Origin blog.csdn.net/qq_43412060/article/details/105240064