Test environment:
Target:x86_64-linux-gnu
GCC version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1)
Defined
To analyze inheritance, you must first know what inheritance is: Inheritance is the most important means of making code reusable in object-oriented Cheng design, which allows programmers to extend and add functionality based on the original class features. The resulting new class is called a derived class (subclass). Inheritance presents the hierarchical structure of object-oriented programming, which embodies the cognitive process from simple to complex.
The inherited format
Class subclass name: Inherit permission base class name
For example, there are two classes defined below:
Class A{public:int Pub;protected:int pro;private:int pri;}; Class B:public a{};
As we said, Class B inherits from Class A, Class B is called Class A's derived class or subclass, Class A is called the base class of Class B, or the parent class.
Inheritance Relationships & Access Qualifiers
Prior to learning the members of the class access qualifiers are aware of public, protected, private these three kinds of access qualifiers, public decorated class members can be accessed outside the class, and protected and private can not. These three types of access also correspond to these three inheritance relationships:
The inheritance relationship can affect the access rights of the member variables inherited from the parent class in the subclass, or on the basis of the last chestnut, we define a Class B object to do the following;
int main () {B B1;b1.pub;b1.pro;b1.pri;return 0;}
The compilation will error:
The pro and PRI variable access permissions are protected and private, and we cannot use them outside of the class. Similarly, a member function is defined in B:
Class B:public A{void fun () {cout<<pub;cout<<pro;cout<<pri;}};
Will report such a mistake:
That is, private members in the base class are not visible in subclasses. The following table summarizes the member access rights for three ways of inheriting:
Summarize:
1. A private member of a base class cannot be accessed in a derived class, and is defined as protected if the base class member does not want to be accessed directly outside the class, but needs to be accessible in the derived class. You can see that the protection member qualifier occurs because of inheritance.
2. Public inheritance is an interface inheritance that maintains the is-a principle, and the members that are available to each parent class are also available to the subclass, because each subclass object is also a parent class object.
3. Protetced/private inheritance is an implementation inheritance, some members of the base class are not completely part of the subclass interface, and are the principle of has-a relationships, so the two inheritance relationships are not used under special circumstances, and are used in most scenarios as public inheritance.
4. Regardless of the inheritance method, the public and protected members of the base class can be accessed inside the derived class, and the private members of the base class exist but are not visible in the subclass (inaccessible).
5. The default inheritance method when using the keyword class is private, and the default inheritance method when using a struct is public, but it is best to show the inheritance in the way it is written.
6. The general use in the actual application is public inheritance, very few scenarios will use Protetced/private inheritance
Construct/destructor Call order in inheritance relationship
On the basis of the existing classes, add the following constructs and destructors:
Class a{public:a () {cout<< "A ()" <<ENDL;} ~a () {cout<< "~a ()" <<ENDL;} Public:int pub;protected:int pro;private:int pri;}; Class B:public a{public:b () {cout<< "B ()" <<ENDL;} ~b () {cout<< "~b ()" <<endl;}};
Then, define an object of Class B in the main function: b b; Compile and run to see the order of the output statements:
First, the base class constructs, then the sub-class constructs, when the destructor first reconstructs the subclass, after the destructor base class. is still the same as before, the first structure of the post-destructor (because on the stack).
Let's walk into the disassembly world of several lines of code:
This is the definition statement that the program now runs to B. = = refers to the assembly statement that is currently running. As you can see, the third Assembly statement invokes the constructor of Class B. Hey? It's not the same order we just saw! No hurry, look down first. Direct NI runs to the third assembly, followed by an SI command:
As you can see, the program calls the Class A constructor before formally entering the Class B constructor, so it can be seen that the compiler automatically invokes the Class A constructor in the initialization list location of Class B's construction number. Or let's read the program:
Sure enough, it went into the constructor of Class A.
The Class B constructor is formally entered after the Class A constructor is out.
When the main function scope is out, the constructor of Class B is called first
A class A constructor is called at the end of a class B constructor. The entire process is consistent with the output information we see.
If there is another member variable in Class B that is a class object, then what is the order of construction and destructor invocation?
Class T{public:t (int i = 1) {cout<< "T ()" <<ENDL;} ~t () {cout<< "~t ()" <<endl;}}; Class a{public:a () {cout<< "A ()" <<ENDL;} ~a () {cout<< "~a ()" <<ENDL;} Public:int pub;protected:int pro;private:int pri;}; Class B:public a{public:b () {cout<< "B ()" <<ENDL;} ~b () {cout<< "~b ()" <<ENDL;} Public: t t;};
Or just the main function, run the program:
It is obvious that the base class construct is called first, then the constructor of the member object, and finally the constructor of the class itself, and the destructor order is reversed. The specific assembly code will not be shown. To summarize:
Description
1. The base class does not have a default constructor, and the derived class must explicitly give the base class name and argument list in the initialization list.
2. If the base class does not have a constructor defined, the derived class can also use the default constructor without defining it.
3. The base class defines the constructor with the formal parameter list, and the derived class must define the constructor function.
Scopes in the inheritance system
- base classes and derived classes are different scopes
- Hidden with the same name: When a child class and parent class have a member of the same name, the subclass member masks the parent class's direct access to the member. (in subclass member functions, you can use the base class:: The base class member accesses the parent class member)
- In practice, it's best not to define members with the same name in the inheritance system.
Inheritance and transformation-assignment compatibility rules-(Prerequisite: Public inheritance)
- Subclass objects can be assigned to parent class objects
- Parent class object cannot be assigned to a subclass object
- A pointer/reference to a parent class can point to a child class object
- A pointer/reference to a subclass cannot point to the parent class object (but can be done by forcing the type conversion)
Friends and inheritance
A friend relationship cannot inherit, which means that the base class friend cannot access the subclass private and protected members.
Class person{ friend void Display (person &p, Student&s);p rotected: string _name;}; Class Student:public person{protected: int _stunum;}; void Display (Person &p, Student &s) { cout<<p._name<<endl; cout<<s._name<<endl; Cout<<s._stunum<<endl;} void TestPerson1 () {person p; Student s; Display (P, s); Error
Inheritance vs. static members
The base class defines a static member, and there is only one such member in the entire inheritance system. No matter how many subclasses are derived, there is only one static member instance.
Single Inheritance & Multiple Inheritance & Diamond Inheritance "single inheritance"
When a subclass has only one direct parent, this inheritance is referred to as a single inheritance.
"Multiple Inheritance"
When a subclass has two or more direct parent classes, this inheritance relationship is called multiple inheritance.
"Diamond Inheritance"
Cases:
Class person{public:string _name;//name};class student:public person{protected:int _num;//Study No.};class Teacher:publi c person{protected:int _id;//employee number};class assistant:public Student, public teacher{protected:string _majorcourse; /Major Course};void Test () {//display specifies which parent class to access assistant A; A.student:: _name = "xxx"; A.teacher:: _name = "yyy";}
Look at the structure of the diamond inheritance and the order in which destructors are called:
Class B and Class C Inherit Class A, Class D inherits classes B and C:
The control object model is clear.
Virtual Inheritance--solving the two semantics of diamond inheritance and the problem of data redundancy
1. Virtual inheritance solves the problem of data redundancy & wasted space of face-class objects containing multiple parent objects in a diamond-like inheritance system.
2. Virtual inheritance systems look complicated, and in practice we don't usually define such a complex inheritance system. It is generally not the last resort to define the virtual inheritance architecture of a diamond structure, because using virtual inheritance to solve data redundancy problems also leads to performance loss.
Actual Storage conditions:
Two addresses are stored in an address that represents a space where the offset from the current address to _name is stored. The specific situation is slightly cumbersome, inconvenient to demonstrate, you can view disassembly.
Look again at the case of virtual inheritance in the above class, construct and destructor call Order: Class B and Class C Virtual inheritance Class A
For the object model, you only need to call the Class B constructor.