Very detailed! Reprint Link
Conversion of C + + base classes to derived classes
In public inheritance, private inheritance, and protection inheritance, only public inheritance preserves the characteristics of the base class well, preserving all members of the base class except constructors and destructors, and the access rights of the public or protected members of the base class are preserved as-is in the derived class. The public member functions of the base class can be called outside the derived class to access the private members of the base class. Therefore, a common derived class has all the functionality of a base class, and all of the functionality that the base class can implement can be implemented by common derived classes. The non-common derived class (private or protected derived class) cannot implement the full functionality of the base class (for example, a public member function that cannot call a base class outside a derived class accesses a private member of the base class). Therefore, only the common derived class is the true subtype of the base class, and it completely inherits the functionality of the base class.
Different types of data can be converted under certain conditions, such as integer data can be assigned to double variables, before the assignment, the integer data is converted into double data, but not an integer data assigned to the pointer variable. This automatic conversion and assignment between different types of data is called assignment compatibility. The question to be discussed now is whether there is an assignment-compatible relationship between the base class and the derived class object, can you convert between types?
The answer is yes. There is an assignment-compatible relationship between the base class and the derived class object, because the derived class contains members that inherit from the base class, so the value of the derived class can be assigned to the base class object, which can be substituted with its subclass object when used with the base class object. Specific performance in the following aspects.
1) Derived class objects can assign values to base class objects
You can assign a value to its base class object with a subclass (that is, a common derived class) object. Such as
// defines a base class A object A1 // An object that defines the common derived class B of Class A B1 // assigning A1 to base class objects using derived Class B object B1
Discards the members of the derived class itself when assigning values. The "overqualified",
In fact, the so-called assignment only assigns values to the data member, and there is no assignment problem with the member function.
Note that the assignment cannot attempt to access the members of the derived class object B1 through object A1, because B1 members are different from the members of the A1. Assuming that age is a common data member added in derived class B, analyze the following usage:
a1.age=23; Error, A1 does not contain additional members in derived classes
b1.age=21; Correct, the B1 contains the added members in the derived class
It should be noted that subtype relationships are unidirectional and irreversible. B is a subtype of a and cannot be said to be a sub-type of B. A subclass object can only be assigned a value on its base class object, and its subclass object cannot be assigned a value using a base class object, because it is obvious that the base class object does not contain members of the derived class and cannot assign a value to the members of the derived class. Similarly, a value cannot be assigned between different derived class objects of the same base class.
2) A derived class object can override a base class object to assign or initialize a reference to a base class object.
// defines a base class A object A1 // defines a common derived class B object B1 // defines the reference variable R for the base class A object and initializes it with A1
At this point, the reference variable r is the alias of A1, and R and A1 share the same storage unit. You can also initialize the reference variable R with a subclass object, changing the last line above to:
// defines the reference variable R for the base class A object and initializes it with the derived Class B object B1
or leave the 3rd line above "a& r=a1;" and re-assign values to r:
// Assigning a reference variable r to A1 with a derived Class B object B1
Note that R is not an alias for B1 at this time, nor does it share the same storage unit with B1. It is just the alias of the base class part of B1, and R shares the same storage unit with the base class part in B1, R and B1 have the same starting address.
3) If a function's argument is a reference to a base class object or a base class object, the corresponding argument can be used with the subclass object.
Such as: there is a function
void // A parameter is a reference variable of an object of Class A { cout<<r.num<<// output data member of this reference variable num
The formal parameter of a function is a reference variable of the object of Class A, which should be an object of Class A. Because the subclass object is assignment-compatible with the derived class object, the derived class object can automatically convert the type, and when the fun function is called, it can be B1 with the object of the derived class B:
Fun (B1);
The value of the base class data member num for the Output Class B object B1.
As before, only the values of the base class members in the derived class can be exported in the fun function.
4) The address of a derived class object can be assigned to a pointer variable that points to a base class object, that is, a pointer variable pointing to a base class object can also point to a derived class object.
[Example] defines a base class student (student), and then defines the common derived class of the Student class graduate (postgraduate), outputting data with pointers to base class objects. The main example of this is that the pointer to the base class object points to the derived class object, in order to reduce the length of the program, only a few members are set in each class. The student class only has num (number), name (name) and score (score) 3 data members, and the graduate class only adds one data member pay (payroll). The procedure is as follows:
#include <iostream>#include<string>using namespacestd;classStudent//declaring the Student class{ Public: Student (int,string,float);//declaring Constructors voidDisplay ();//declaring output FunctionsPrivate: intnum; stringname; floatscore;}; Student::student (intNstringNamfloatS//Defining Constructors{num=N; Name=Nam; Score=s;}voidStudent::d isplay ()//Defining output Functions{cout<<endl<<"Num:"<<num<<Endl; cout<<"Name:"<<name<<Endl; cout<<"Score:"<<score<<Endl;}classGraduate: PublicStudent//declaring a common derived class graduate{ Public: Graduate (int,string,float,float);//declaring Constructors voidDisplay ();//declaring output FunctionsPrivate: floatPay//Wages};//Defining ConstructorsGraduate::graduate (intNstringNamfloatSfloatp): Student (n,nam,s), Pay (p) {}voidGraduate::d Isplay ()//Defining output Functions{Student::d isplay ();//call the display function of the student classcout<<"pay="<<pay<<Endl;}intMain () {Student stud1 (1001,"Li",87.5);//defines the Student class object Stud1Graduate Grad1 (2001,"Wang",98.5,563.5);//defines the Graduate class object Grad1Student *pt=&stud1;//defines a pointer to a student class object and points to Stud1Pt->display ();//Call the Stud1.display functionpt=&grad1;//pointer pointing to Grad1Pt->display ();//Call the Grad1.display function}
The following analysis of the program is very important, please read and think carefully.
Many readers will assume that there are two display member functions with the same name in the derived class, and that, depending on the rule overridden by the same name, the display function of the derived class graduate object should be called, and student is called during the execution of graduate::d isplay function: Display function, output num,name,score, and then output the pay value.
In fact, this inference is wrong, first look at the output of the program:
Num:1001name:liscore:87.5 num:2001Name:wangscore:98.5
The first 3 lines are the student STUD1 data, and the last 3 lines are the graduate grad1 data, and no pay value is output.
The problem is that PT is a pointer variable that points to the student class object, even if it points to grad1, but actually PT points to the part of Grad1 that inherits from the base class.
By pointing to a pointer to a base class object, you can access only the base class members in the derived class, and you cannot access the added members of the derived class. So Pt->display () does not call the display function added by the derived class graduate object, but the display function of the base class, so it only outputs Num,name,score3 data for graduate grad1.
If you want to output graduate Grad1 pay through the pointer, you can set a pointer variable ptr to a derived class object, point it to Grad1, and then invoke the display function of the derived class object with Ptr->display (). But it's not very convenient.
In this example, it is legal and safe to point a pointer variable to a base class object to the child class object, and there will be no compile error. But the application does not fully satisfy people's hopes, and people sometimes want to be able to invoke the members of the base class and subclass object by using a base class pointer. If this can be done, the program staff will be very convenient. Subsequent chapters will address this issue. The solution is to use virtual functions and polymorphism.
An explanation of C + + virtual base class
Naming conflicts are easy to generate when multiple inheritance occurs, even if we carefully name the member variables and member functions in all classes as different names, the naming conflict can still occur, such as the very classic diamond inheritance hierarchy. As shown in the following:
Class A derives from Class B and Class C, and Class D inherits from Class B and Class C, when the member variables and member functions in Class A inherit into Class D into two copies, one from A-->b-->d and the other from A-->c-->d.
Retaining multiple copies of the same name in a derived class for the indirect base class, although you can store different data in different member variables, in most cases this is superfluous: because preserving multiple member variables not only takes up more storage space, it is also prone to naming conflicts, and there are few such requirements.
To solve this problem, C + + provides a virtual base class that preserves only one member of the indirect base class in the derived class.
To declare the virtual base class to precede the inherited method with the virtual keyword, consider the following example:
#include <iostream>using namespacestd;classa{protected: intA; Public: A (inta): A (a) {}};classB:Virtual Publica{//declaring a virtual base classprotected: intb; Public: B (intAintb): A (a), B (b) {}};classC:Virtual Publica{//declaring a virtual base classprotected: intC; Public: C (intAintc): A (a), C (c) {}};classD:Virtual PublicBVirtual Publicc{//declaring a virtual base classPrivate: intD; Public: D (intAintBintCintD): A (a), B (b), C (A,c), D (d) {}voiddisplay ();};voidD::d isplay () {cout<<"a="<<a<<Endl; cout<<"b="<<b<<Endl; cout<<"c="<<c<<Endl; cout<<"d="<<d<<Endl;}intMain () {(NewD1,2,3,4)),display (); return 0;}
Operation Result:
A=1b=2c=3d=4
In this case, we used the virtual base class, where there is only one copy of member variable A in the derived class D, so you can access a directly in the display () function without the addition of the class name and the domain resolver.
Note that the constructor for the derived class D differs from the previous usage. In the past, the constructor of a derived class simply had to be responsible for initializing its direct base class, and then its direct base class was responsible for initializing the indirect base class. Now, because the virtual base class has only one copy of the member variable in the derived class, the initialization of the member variable must be given directly by the derived class. If the virtual base class is not initialized directly by the last derived class, and the virtual base class is initialized by a direct derived class of the virtual base class (such as Class B and Class C), it is possible that there is a contradiction between the different initialization parameters of the virtual base class in the constructors of Class B and Class C. So the rule: in the last derived class not only is responsible for its direct base class initialization, but also responsible for the virtual base class initialization.
Some readers will ask: the constructor of Class D is called by the initialization table to the virtual base class constructor A, and the constructors of Class B and Class C also call the virtual base class constructor A through the initialization table, so that the constructor of the virtual base class is not called 3 times? You don't have to worry about it. The C + + compilation system only performs calls to the constructor of the virtual base class from the last derived class, ignoring other derived classes of the virtual base class (such as Class B and class C) calls to the virtual base class's constructor, which guarantees that the data members of the virtual base class are not initialized more than once.
Finally, note: In order to ensure that the virtual base class inherits only once in the derived class, it should be declared as a virtual base class in all the direct derived classes of the base class, otherwise multiple inheritance of the base class will still occur.
As you can see: Use multiple inheritance with great care, and often there are two of semantic issues. The above example is simple, if the derivation of a bit more, multiple inheritance more complex, the programmer is easy to mihunzhen, programming, debugging and maintenance work will become more difficult. Therefore, many programmers do not advocate the use of multiple inheritance in the program, only when it is relatively simple and not easy to appear two of the semantic or is necessary to use multiple inheritance, the problem can be solved with single inheritance do not use multiple inheritance. For this reason, many object-oriented programming languages (such as Java, Smalltalk, C #, PHP, and so on) after C + + do not support multiple inheritance.
A detailed description of the transformation of base and derived classes in C + + and virtual base classes