#include <iostream>#include<time.h>using namespacestd;//base class B1classb1{ Public: B1 (inti) {cout<<"Constructing B1"<<i<<Endl; } ~B1 () {cout<<"destructing B1"<<Endl; }};//base class B2classb2{ Public: B2 (intj) {cout<<"Constructing B2"<<j<<Endl; } ~B2 () {cout<<"destructing B2"<<Endl; }};//base class B3classb3{ Public: B3 () {cout<<"Constructing B3"<<Endl; } ~B3 () {cout<<"destructing B3"<<Endl; }};//derived class C, inherited B2, B1,B3 (declaration order from left to right. B2->B1->B3)classC: PublicB2, PublicB1, Publicb3{ Public: C (intAintBintCintd): B1 (a), memberB2 (d), memberB1 (c), B2 (b) {//b1,b2 Constructors have parameters, B3 constructors have no arguments//memberB2 (d), memberB1 (c) is the process by which a derived class initializes its own data member,//Constructor execution order, base class (declaration order) Constructors for inline member objects (Declaration order), content in derived class constructors }Private: B1 memberB1; B2 memberB2; B3 memberB3;};intMain () {C obj (1,2,3,4); return 0; }/*Output Results*//*Constructing B2 2constructing B1 1constructing b3constructing B1 3constructing B2 4constructing b3destructing b3dest Ructing b2destructing b1destructing b3destructing b1destructing B2*/View CodeThe question of ambiguityUnder single inheritance, the public and protected members of the base class can be accessed directly, just as they are members of a derived class, which is also true for multiple inheritance. However, under multiple inheritance, a derived class can inherit a member of the same name from two or more base classes. In this case, however, direct access is differentiation and will result in compile-time errors.
Example:
#include <iostream>using namespacestd;classa{ Public:voidf ();};classb{ Public:voidf ();voidg ();};classC: PublicA Publicb{ Public:voidg ();voidh ();};intMain () {C C1; //c1.f (); Generate two semantic questions, access the F () in a F () of or B? //qualify elimination ambiguity by specifying a member nameC1. A::f (); C1. B::f ();}View CodeYou can eliminate ambiguity by using the member name qualifier, but a better solution is to define a function f () with the same name in Class C, and F () in class C to call A::f() or, as necessary B::f() , to c1.f() invoke C::f() .
When a derived class derives a class from more than one base class, and these base classes have a common base class, there may also be two semantics when accessing the members described in the base class.
Example:
//derived classes b1,b2 inherit the same base class A, derived class C inherits B1, B2classa{ Public:intA;};classB1: Publica{Private:intB1;};classB2: Publica{Private:intB2;};classE | PublicB1, Publicb2{ Public:intf ();Private:intc;};intMain () {C C1; C1.a (); C1. A::a (); C1. B1::a (); C1. B2::a (); return 0;}View Codec1.a;c1.A::a;Both of these accesses are of two semantics and c1.B1::a; c1.B2::a; are correct:
The member functions of Class C f() can be eliminated ambiguity by the following definitions:
int c::f () { + b2::a;}
View CodeFor the reason of ambiguity, a class cannot inherit more than one time from the same class directly.
Virtual base classNaming 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:
Graph TD; a-->b; a-->c; b-->d; c-->d;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. When d accesses data inherited from a, it becomes impossible to decide which route to pass the data, so there is a virtual base class.
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. Using a virtual base class allows you to keep only one member of the indirect base class in the derived class.
Declaring a virtual base class requires only the virtual keyword to precede the inherited method, as in 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;}/*running Result: a=1b=2c=3d=4*/View CodeIn 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.
Initialization of virtual base class
: 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.
In the preceding code, the constructor of Class D calls out the constructor a of the virtual base class by initializing the table, 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.
Assignment compatibility principleAssignment compatible
Assignment compatibility rules are substituted for objects of a public derived class that can be used anywhere a base class object is needed.
The overrides referred to in the assignment compatibility rule include:
- The object of a derived class can be assigned to a base class object;
- An object of a derived class can initialize a reference to a base class;
- The address of a derived class object can be assigned to a pointer to a base class.
After the override, the derived class object can be used as an object of the base class, but only members that inherit from the base class are used.