Virtual base class, pure virtual function and abstract class
1. virtual base class
In the example mentioned in "Multi-inheritance", Class A, CLASS B1, Class B2, and class C constitute the hierarchy of class inheritance. In this structure, the object of class C will contain sub-objects of Two Classes. Because Class A is A public base class on the two inheritance paths of the derived class C, this public base class will generate multiple base class sub-objects in the object of the derived class. If you want this public base class to generate only one base class sub-object in the derived class, you must set this base class to a virtual base class.
Introduction and description of virtual base classes
The previous section briefly introduced the reasons for introducing the virtual base class. In fact, the real purpose of introducing the virtual base class is to solve the problem of ambiguity.
The description format of the virtual base class is as follows:
Virtual <Inheritance Method> <Base Class Name>
Among them, virtual is the keyword of the virtual class. The description of the virtual base class is written after the name of the derived class when the derived class is defined. For example:
Class
{
Public:
Void f ();
Protected:
Int;
};
Class B: virtual public
{
Protected:
Int B;
};
Class C: virtual public
{
Protected:
Int c:
};
Class D: public B, public C
{
Public:
Int g ();
Private:
Int d;
};
Because the virtual base class is used, the relationship between Class A, Class B, Class C and Class D is shown as follows in the DAG graph:
A {f (),}
//
B {B} C {c}
//
D {g (), d}
From this figure, we can see that the virtual base class sub-objects of different inheritance paths are merged into an object. This is the role of the virtual base class, which eliminates the possible ambiguity before merging. In this case, only one class A object exists in the Class D object. Therefore, the following references are correct:
D n;
N. f (); // The reference to f () is correct.
Void D: g ()
{
F (); // The reference to f () is correct.
}
The following sections are correct.
D n;
A * pa;
Pa = & n;
In this example, pa is A pointer to an object of Class A, n is an object of class D, and n is the address of the n object. Pa = & n is the object that points the pa pointer to Class D. This is correct and has no ambiguity.
Constructor of the virtual base class
As mentioned above, in order to initialize the sub-objects of the base class, the constructor of the derived class must call the constructor of the base class. For the virtual base class, because the object of the derived class has only one virtual base class sub-object. To ensure that the virtual base class sub-object is initialized only once, the virtual base class constructor must be called only once. Because the hierarchy of the inheritance structure may be deep, it is required that the class specified when the object is created is called the most derived class. C ++ stipulates that the sub-objects of the virtual base class are initialized by the constructor of the most derived class by calling the constructor of the virtual base class. If a derived class has a direct or indirect virtual base class, the initial list of the constructor members of the derived class must list the calls to the virtual base class constructor. If not listed, it indicates that the default constructor of the virtual base class is used to initialize the virtual base class sub-objects in the object of the derived class.
The call of this virtual base class constructor must be listed in the member initialization list of the constructor In the derived class that is directly or indirectly inherited from the virtual base class. However, only the constructor of the most derived class used to create an object calls the constructor of the virtual base class, the constructor calls to this virtual base class listed in the base class of the derived class are ignored during execution. This ensures that the object of the virtual base class is initialized only once.
C ++ also stipulates that a call to the virtual base class and non-virtual base class constructor will appear in the member initialization list, then, the constructor of the virtual base class is executed before the constructor of the non-virtual base class.
The following example describes how to use constructors of a derived class with a virtual base class.
# Include <iostream. h>
Class
{
Public:
A (const char * s) {cout <s <endl ;}
~ A (){}
};
Class B: virtual public
{
Public:
B (const char * s1, const char * s2): A (s1)
{
Cout <s2 <endl;
}
};
Class C: virtual public
{
Public:
C (const char * s1, const char * s2): A (s1)
{
Cout <s2 <endl;
}
};
Class D: public B, public C
{
Public:
D (const char * s1, const char * s2, const char * s3, const char * s4)
: B (s1, s2), C (s1, s3), A (s1)
{
Cout <s4 <endl;
}
};
Void main ()
{
D * ptr = new D ("class A", "class B", "class C", "class D ");
Delete ptr;
}
The output result of this program is:
Class
Class B
Class C
Class D
The virtual base class is used in the derived classes B and C, so that the created Class D object has only one virtual base class sub-object.
The constructor Class A contains the constructor in the member initialization list of the constructor Class B, C, and D.
When a Class D object is created, only the virtual base class constructor listed in the initialization list of the Class D constructor is called and called only once, the virtual base class constructor listed in the member initialization list of the Class D-based constructor is not executed. This can be seen from the output results of the program.
2. Pure virtual functions and abstract classes
A pure virtual function is a special virtual function. Its general format is as follows:
Class <class Name>
{
Virtual <type> <Function Name> (<parameter table>) = 0;
...
};
In many cases, virtual functions cannot be meaningful and implemented in the base class, but it is described as pure virtual functions. Its implementation is left to the derived class of the base class. This is the role of pure virtual functions. The following is an example of a pure virtual function.
# Include <iostream>
Class point
{
Public:
Point (int I = 0, int j = 0) {x0 = I; y0 = j ;}
Virtual void set () = 0;
Virtual void draw () = 0;
Protected:
Int x0, y0;
};
Class line: public point
{
Public:
Line (int I = 0, int j = 0, int m = 0, int n = 0): point (I, j)
{
X1 = m; y1 = n;
}
Void set () {std: cout <"line: set () called. \ n ";}
Void draw () {std: cout <"line: draw () called. \ n ";}
Protected:
Int x1, y1;
};
Class ellipse: public point
{
Public:
Ellipse (int I = 0, int j = 0, int p = 0, int q = 0): point (I, j)
{
X2 = p; y2 = q;
}
Void set () {std: cout <"ellipse: set () called. \ n ";}
Void draw () {std: cout <"ellipse: draw () called. \ n ";}
Protected:
Int x2, y2;
};
Void drawobj (point * p)
{
P-> draw ();
}
Void setobj (point * p)
{
P-> set ();
}
# Include <iostream>
# Include "test. h"
Using namespace std;
Int main ()
{
Line * lineobj = new line;
Ellipse * elliobj = new ellipse;
Drawobj (lineobj );
Drawobj (elliobj );
Cout <endl;
Setobj (lineobj );
Setobj (elliobj );
Cout <"\ nRedraw the object... \ n ";
Drawobj (lineobj );
Drawobj (elliobj );
Return 0;
}
Abstract class
Classes with pure virtual functions are called abstract classes. An abstract class is a special class established for the purpose of abstraction and design. It is at the upper layer of the hierarchy of inheritance. Abstract classes cannot define objects. In practice, to emphasize that a class is an abstract class, you can describe the constructor of this class as a protected access control permission.
The main function of an abstract class is to organize the relevant organizations in an inheritance hierarchy to provide them with a public root. The related subclass is derived from this root.
Abstract classes depict the General Semantics of the Operation interfaces of a group of child classes. These semantics are also passed to child classes. In general, an abstract class only describes the operation interfaces of this group of sub-classes, and the complete implementation is left to the sub-classes.
An abstract class can only be used as a base class. The implementation of its pure virtual function is provided by the derived class. If the derived class does not redefine the pure virtual function, and the derived class only inherits the pure virtual function of the base class, the derived class is still an abstract class. If the implementation of the basic class pure virtual function is provided in the derived class, the derived class is no longer an abstract class. It is a concrete class that can create objects.