[C++] Summary of inherited knowledge points

1. The concept and definition of inheritance

1.1 The concept of inheritance

Inheritance (inheritance) mechanism is the most important means for object-oriented programming to make code reusable. It allows programmers to expand and increase functions while maintaining the original characteristics of the class, thus generating new classes, called derived classes. Inheritance presents the hierarchical structure of object-oriented programming and embodies the cognitive process from simple to complex. In the past, the reuse we touched was all function reuse, and inheritance was the reuse of class design level. For example, to better understand what inheritance is:
Insert picture description here
there are now three types of students, teachers, and teaching assistants. They have their own member variables and member functions. Three pieces of code are required to implement these three classes, but is it a bit redundant? Because they have the same function (red box). Look at the following picture again: If you
Insert picture description here
look at it this way, is it better? It is equivalent to the following three parts inheriting the above, and the repeated part can be written once.

1.2 Definition of inheritance

1.2.1 Define format

Below we see that Person is the parent class, also known as the base class. Student is a subclass, also called a derived class:
Insert picture description here

1.2.2 Inheritance and access qualifiers

Insert picture description here

1.2.3 Inheritance of changes in the access method of base class members

Insert picture description here
to sum up:

  1. The private members of the base class are not visible in the derived class no matter how they are inherited. The invisible here means that the private members of the base class are still inherited from the derived class object, but the grammatically restricts the derived class object from accessing it no matter whether it is inside or outside the class;
  2. Private members of the base class cannot be accessed in the derived class. If the members of the base class do not want to be accessed directly outside the class, but need to be accessible in the derived class, they are defined as protected. It can be seen that the protected member qualifier only appears because of inheritance;
  3. The default inheritance method when using the keyword class is private, and the default inheritance method when using struct is public;
  4. . In practical applications, public inheritance is generally used, and protetced/private inheritance is rarely used.
//class Student : public Person
//class Student : protected Person
//class Student : private Person

Two, base class and derived class object assignment conversion

  1. Derived class objects can be assigned to base class objects/base class pointers/base class references; base class objects cannot be assigned to derived class objects.
  2. You can use base class pointers or references to objects of derived classes, but not vice versa

Three, the scope of inheritance

In the inheritance system, the base class and the derived class have independent scopes.
Hidden with the same name: For members (member functions or member variables) with the same name in the subclass and base class, it should be noted that if the member function is hidden, only the function name is the same to form a hidden member. Show it through a piece of code:

// B中的fun和A中的fun不是构成重载,因为不是在同一作用域
// B中的fun和A中的fun构成隐藏,成员函数满足函数名相同就构成隐藏。
class A
{
    
    
public:
	void fun()
	{
    
    
		cout << "func()" << endl;
	}
};
class B : public A
{
    
    
public:
	void fun(int i)
	{
    
    
		A::func();
		cout << "func(int i)->" << i << endl;
	}
};
void Test()
{
    
    
	B b;
	b.fun(10);
};

Fourth, the default member function of the derived class

There are 6 default member functions. "Default" means that we don't write one, and the compiler automatically generates one. Then in the derived class, how are these member functions generated?

  1. The constructor of the derived class must call the constructor of the base class to initialize that part of the members of the base class. If the base class does not have a default constructor, it must be called in the initialization list stage of the derived class constructor;
class Base
{
    
    
public:
	Base(int b)
		: _b(b)
	{
    
    
		cout << "Base()" << endl;
	}
protected:
	int _b;
};
class Derived : public Base
{
    
    
public:
	Derived(int b, int d)
		: Base(b)// 初始化基类部分继承下来的成员
		, _d(d)
	{
    
    
		cout << "Derived()" << endl;
	}
protected:
	int _d;
};
  1. The copy constructor of the derived class must call the copy constructor of the base class to complete the copy initialization of the base class;
class Base
{
    
    
public:
	Base(int b)
		: _b(b)
	{
    
    
		cout << "Base()" << endl;
	}
	Base(const Base& b)
		: _b(b._b)
	{
    
    }
protected:
	int _b;
};
class Derived : public Base
{
    
    
public:
	Derived(int b,int d)
		: Base(b)
		, _d(d)
	{
    
    }
	Derived(const Derived& d)
		: Base(d)
		, _d(d._d)
	{
    
    }
protected:
	int _d;
};
  1. The operator= of the derived class must call the operator= of the base class to complete the copy of the base class;
class Base
{
    
    
public:
	Base(int b)
		: _b(b)
	{
    
    
		cout << "Base()" << endl;
	}
	Base& operator=(const Base& d)
	{
    
    
		if (this != &d)
		{
    
    
			_b = d._b;
		}

		return *this;
	}
protected:
	int _b;
};
class Derived : public Base
{
    
    
public:
	Derived(int b,int d)
		: Base(b)
		, _d(d)
	{
    
    }
	Derived& operator=(const Derived& d)
	{
    
    
		if (this != &d)
		{
    
    
			__super::operator=(d);
			_d = d._d;
		}
		return *this;
	}
protected:
	int _d;
};
  1. The destructor of the derived class will automatically call the destructor of the base class to clean up the members of the base class after being called. Because this can ensure that the derived class objects first clean up the derived class members and then clean up the order of the base class members;
  2. To initialize the derived class object, first call the base class structure and then call the derived class structure;
  3. Derived class object destruction cleanup calls the derived class destruction first and then adjusts the base class destruction.

Five, inheritance and friends, static functions

  1. Friendship cannot be inherited, because friends are not members of the class;
  2. Common member variables and functions can be inherited to subclasses;
  3. Static member variables and functions can also be inherited by subclasses

6. Complex diamond-shaped inheritance and diamond-shaped virtual inheritance

6.1 Single inheritance

Single inheritance: The subclass has only one base class.
Insert picture description here

6.2 Multiple inheritance

Multiple inheritance: subclasses have at least two base classes

class B1;
class B2;
class D : public B1, public B2;
//多个基类前的访问限定符不能省略,如果没有写则是默认的访问权限

Insert picture description here
Note : If it is multiple inheritance, the order of the members in the base class in the subclass is consistent with the order of the base class in the inheritance list.

6.3 Diamond inheritance

Insert picture description here
The derived class D contains two _bs, one is inherited from the C1 base class, and the other is inherited from the C2 base class. but:

D d;
d._b = 1;//编译器不知道放到从哪个基类中继承下来的_b,因此产生二义性

The ambiguity of diamond inheritance can be embodied in member variables or member functions. So how to solve it? There are two ways:

  1. To make the access clear, just add the name of the base class before the ambiguous member. This approach does not essentially solve the problem, because the members of the top-level base class still have two shares in the bottom-level subclass.
  2. Let the member variables in the topmost base class store only one copy in the bottommost subclass. So the concept of diamond virtual inheritance

Virtual inheritance : add the virtual keyword before inheriting permissions.
We know that ordinary inheritance is the addition of base classes and subclasses; while virtual inheritance adds a virtual base table pointer, which points to an offset table, also called a virtual base table.
Insert picture description here
If you access the members of the base class through a derived class object, first take out the address (the address of the virtual table pointer) from the first 4 bytes of the object, and then shift the address backward by 4 bytes, and take out the content of the space (offset ), so that the object address is shifted back by the corresponding offset (8) bytes, and you get the member variables inherited from the base class in the subclass object.

The only function of virtual inheritance: it is used in diamond inheritance to solve the ambiguity problem of diamond inheritance. Diamond virtual inheritance:
Insert picture description here

7. Summary and reflection on inheritance

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 are problems in complexity and performance.

Inheritance and composition:
Public inheritance is an is-a relationship, which means that each derived class object is a base class object; composition is a has-a relationship. Suppose B combines A, and there is an A object in each B object. Actually use as many combinations as possible. The combination of low coupling and good code maintainability. However, inheritance is also useful. If some relationships are suitable for inheritance, use inheritance. In addition, to achieve polymorphism, inheritance is also necessary. The relationship between classes can use inheritance, you can use composition, just use composition.

// Car和BMW Car和Benz构成is-a的关系
class Car
{
    
    
protected:
	string _colour = "白色"; // 颜色
	string _num = "陕ABCDEF"; // 车牌号
};

class BMW : public Car
{
    
    
public:
	void Drive() {
    
    cout << "好开-操控" << endl;}
};

class Benz : public Car
{
    
    
public:
	void Drive() {
    
    cout << "好坐-舒适" << endl;}
};

 // Tire和Car构成has-a的关系
class Tire
{
    
    
protected:
	string _brand = "Michelin"; // 品牌
	size_t _size = 17; // 尺寸
};

class Car
{
    
    
protected:
	string _colour = "白色"; // 颜色
	string _num = "陕ABCDEF"; // 车牌号
	Tire _t; // 轮胎
};

Guess you like

Origin blog.csdn.net/zhao_leilei/article/details/110948754