Two or three things about C++ inheritance

inheritance definition

Inheritance mechanism is the most important means of object-oriented programming to make code reusable. It allows programmers to extend and add functions on the basis of maintaining the characteristics of the original class, so as to generate new classes, which are called derived classes

Inheritance is a relationship of is a, the subclass (derived class) inherits the parent class (base class), and the subclass has the same properties as the parent class:

所以子类可以使用父类的方法,父类的成员变量也拷贝到了子类!

Define the format

     派生类  继承方式   基类 

class subclass : public parentclass {}

Inheritance

insert image description here
Permission: public>protected>private
The permission of the parent class and the permission of the inheritance method take the minimum permission, which is the member permission of the subclass

The public can access
the protected class and cannot access it, but the subclass can access
the private class and cannot access it, and the subclass cannot see it.

Invisible:
The "member" in the parent class is still copied to the subclass, and the subclass cannot access it, but there is a memory in the subclass

Base class and derived class object assignment conversion

This part is the most important part of inheritance. If I don't fully understand this part, there must be problems with inheritance, and polymorphism must be confused
. Let me explain my personal understanding. If there are any problems, please correct me.

1. The base class cannot be assigned to the derived class
2. The derived class object can be assigned to the object/pointer/reference of the base class, there is an image called slice or cut

1:
The members contained in the base class must be less than or equal to the derived class. This is similar to the assignment of the this pointer of the class and the object. Only the permissions are allowed to be reduced, and the permissions are not allowed to be expanded.

2:
① The derived class assigns the object of the base class

#include<iostream>
using namespace std;
class A
{
    
    
public:
	void show()//切片
	{
    
    
		cout << _age << endl;
	}
protected:
	int _age=10;
};
class B :public A
{
    
    
public:
	int _num;
};
int main()
{
    
    
	B b;//派生类
	A a=b;//基类
}

insert image description here
It can be seen that the derived class inherits A, and there is
a truncation (slicing) when the derived class is assigned to the base class with a unique member _num

a is a specific class, it will open up another space for the parent class object (this will be used in the polymorphism principle), and copy the members of the parent class in the derived class, the virtual function pointer will not be copied, a is a concrete class with a virtual function pointer unique to A

②The pointer/reference assigned by the derived class to the base class

In this case, the pointer will point to the part of the derived class that is common to the parent class

Like this:
insert image description here
the pointer and reference can only access the public parts of the parent class, and only the inherited parent class members

#include<iostream>
using namespace std;
class A
{
    
    
public:
	//A:this *= B:this*;
	void show()//切片
	{
    
    
		cout << _age << endl;
	}
protected:
	int _age=10;
};
class B :public A
{
    
    
	
public:

	int _age = 20;
	int _num;
};
int main()
{
    
    
	//1
	B b1;
	b1.show();
	//2
	A* a1 = &b1;
	a1->show();
	//3
	A& a2 = b1;
	a2.show();
	
	return 0;
}

The internal structure of b1,a1
insert image description here

After instantiating b1, b1 calls the show function, and the derived class can call the function of the parent class. At this time, the this pointer of the parent class = the this pointer of the subclass, and the slicing behavior occurs, and this pointer can only be accessed from the parent class. down members, cannot access the unique members of the subclass

In addition, subclasses and superclasses have unique scopes. There are members of the same name in subclasses and superclasses. Subclass members will block direct access to members of the same name by the superclass. This situation is called hiding, also called redefinition.

So from the above figure, we can see that there are two _ages in b1, the one inherited from A is equal to 10, and the one that is redefined is equal to 20, so the 10 inherited from the parent class is printed.

In the same way, 2 and 3 also occur slices, and the pointer to call the function can only access the members inherited from the base class instead of the redefined 20

operation result:
insert image description here

Then if we modify class B, the first step will print 20,
insert image description here
insert image description here

Because the parent class inherits 10, in the constructor, modify the parent class to inherit 20

diamond inheritance

Single inheritance and multiple inheritance:

Single inheritance: When a subclass has only one direct parent class, the inheritance relationship is called single inheritance
insert image description here

Multiple inheritance: When a subclass has two or more direct parent classes, the inheritance relationship is called multiple inheritance
insert image description here
Diamond inheritance: Diamond inheritance is a special case of multiple inheritance
insert image description here

The problem with diamond inheritance (pit)

#include<iostream>
using namespace std;
class A
{
    
    
public:
	int _a;
};
class B :public A
{
    
    
public:
	int _b;
};
class C :public A
{
    
    
public:
	int _c;
};
class D :public B, public C
{
    
    
	int _d;
};
int main()
{
    
    
	D d;
	//d._a = 10; 二义性编译器不知道调用从B还是C中继承而来的_a
	
	return 0;
}

d's class membership model:
insert image description here

insert image description here

It can be seen that D inherits _a from B and _a from C, resulting in data redundancy .
When we access d._a, the compiler does not know which _a to access, which results in Ambiguity

If it is solved in the following way:
insert image description here
insert image description here
although _a can be accessed by specifying the scope, the ambiguity can be solved, but the redundancy cannot be solved. A class has two copies of the same member variable, which is not allowed

In order to solve this problem
, virtual inheritance is proposed (it has nothing to do with virtual functions)
insert image description here

#include<iostream>
using namespace std;
class A
{
    
    
public:
	int _a;
};
class B :virtual public A
{
    
    
public:
	int _b;
};
class C :virtual public A
{
    
    
public:
	int _c;
};
class D :public B, public C
{
    
    
	int _d;
};
int main()
{
    
    
	D d;
	d._a = 20;
	cout << d._a << endl;
	d.B::_a = 10;
	cout << d.B::_a << endl;
	return 0;
}

After the program executes d._a=20,
insert image description here
from the monitoring window:
after virtual inheritance, you can see that _a in d is assigned at the same time , there is no ambiguity, and there is no redundancy, which is equivalent to only one piece of data

How C++ Compilers Solve the Ambiguity and Redundancy of Virtual Inheritance

You can't really see the real situation through the monitor window, the compiler has been processed, so you
can view it through the memory window

①: It is not the case of virtual inheritance . There are two addresses of _a
insert image description here
insert image description here
in the ordinary diamond inheritance. ② The situation of virtual inheritance

Please add image description
insert image description here

_a is placed at the bottom

In virtual inheritance, two _a share an address, which solves data redundancy and ambiguity

But there are two more lines of data in the B and C areas, this line is exactly four bytes

It's easy to think of a pointer, so what does it point to?
let me take you to research

Virtual base table:
insert image description here
It can be seen that the next position pointed to is 20, 12 , which correspond to the offsets of the pointers
(virtual base table pointers) in B and C to the common base class _a respectively

So what's the use of this?

D d;
B b=d;
C c=d;

Like this, b, c are sliced, and this offset is needed to find the common _a.

The first line is all zero, which is the offset reserved for the polymorphic virtual table (polymorphism is introduced again)

Guess you like

Origin blog.csdn.net/hbbfvv1h/article/details/120959839