A class, if there is no constructor for the user declaration, then a default constructor is implicitly declared. The implicit declaration of the constructor, exactly when to be synthesized, by the compiler composition of the default constructor exactly what to do, how the compiler handles user-defined constructors, this is the issue to be explored.
1. When the default constructor is synthesized
if a class does not have any user-declared constructors, then when the compiler needs it, the compiler will synthesize a default constructor for the class that is used only to perform the operations required by the compiler. Note that the default constructor is synthesized when the compiler needs it, not when the program needs it, and the default constructor should be implemented by the programmer if the program requires it.
So when does the compiler need it? correctly, the compiler needs to have a default constructor for the following four types of classes when it encounters four situations:
1) The member variable of the class has a default constructor
2) class base class with default constructor
3) class with virtual function
4) class with a virtual base class
Synthetic operations are synthesized only when the constructor really needs to be called.
Now there is one more question: How does the compiler avoid compositing multiple defaults in the various compilation modules in C + +? The solution is to complete the default constructors, copy constructors, destructors, assignment operators, and so on, in the form of inline. If the function is too complex to be made into inline, it becomes an explicit non-inline static function. Both inline and non-inline static functions are intended to not be accessed by people outside the file.
for the following procedure:
Class x{public : int mdata;
class X does not declare any constructors, but it does not belong to the 4 types of classes mentioned above, so the compiler does not synthesize a default constructor for Class X.
The following is a detailed analysis of the behavior of the compiler's default constructors for the above 4 types of classes.
2.the member variable of the class has a default constructor (that is, the class contains the Member class object (Member class Objects ))
This situation refers to a class that does not have any constructors, but whose member variables are variables of a class with a default constructor.
For example, the following code shows:
Class x{public : X () {mdata = 0; cout << "x::x ()" << Endl;} int mdata;}; Class xs{public : X MX; int MN;}; int main () { xs xs; cout << xs.mX.mData << Endl; cout << xs.mn << Endl;
The class XS does not define any constructors, but its member variable MX is type X, and Class X has a default constructor that runs as follows:
As can be seen from the running result, in the compiler's default constructor for the class Xs composition, the constructor called X is initialized for its member variable MX, but the composition's default constructor does not initialize the member variable MN of class XS. As can be seen, the constructor for the class Xs is composed by the compiler as shown in the following pseudo code:
Inline Xs::xs () { mx.x::x ();}
Sometimes we define a default constructor for a class, but in that constructor, only the part of the member variable is initialized, what kind of behavior and effect happens? Keep the test code of Class X and main function unchanged, the code for the modified class XS is as follows:
Class xs{public : Xs () { cout << "Xs::xs ()" << Endl; MN = 1; } X MX;
As you can see, we have added a default constructor for class Xs, but in this constructor we initialize the member variable MN only, and the result is as follows:
as can be seen from the running result, although we do not have the MX initialized in the default constructor of the class Xs, the default constructor for Class X is called, and its invocation order is preceded by the class XS default constructor function body code.
Thus, the compiler behaves: if the class contains one or more class member objects (Member class object), each constructor of the class must invoke the default constructor for each class member (in order of member declaration). The compiler expands the existing constructor, placing some code in it so that the user's code is called the default constructor of the necessary class member before it is executed.
the following pseudo-code is used for the constructor of class XS at this time:
Inline Xs::xs () { mx.x::x (); cout << "Xs::xs ()" << Endl;
For such cases, the compiler synthesizes the default constructor or inserts code into an existing default constructor in the sense that each class member variable is initialized.
3. Class base class with default constructor
This situation refers to a class that does not have any constructors derived from a class with a default constructor.
For example, the following code shows:
Class x{public : X () {mdata = 0; cout << "x::x ()" << Endl;} int mdata;}; Class Xx:public x{public : int mN;}; Class Xxx:public Xx{};int Main () { xx xx; cout << xx.mdata << Endl; cout << xx.mn << Endl; xxx xxx; return 0;}
class XX does not have any constructors, but its base class X has a default constructor that runs as follows:
as you can see from the running result, the constructor of the compiler composition calls the default constructor of the previous layer base class. For a successor class, the default constructor for this composition is the same as a default constructor that is explicitly provided.
if the designer of a class provides one or more constructors (including a default constructor), but does not explicitly call its base class constructor in its provided constructor, what does the compiler do with it?
add two constructors for class XX and modify the test code of the main function as follows:
Class Xx:public x{public : XX () { MN = 1; } XX (int n) { MN = n; } int MN;}; int main () { XX xx1; XX xx2 (2);
The constructors for class XX do not explicitly call the constructors of their base classes. The results of the operation are as follows:
from the running results can be proved that: the compiler will expand each of the derived classes of the current constructor, will be called all the necessary default construction of the program code inserted. Note: Because a user-defined constructor already exists, the compiler no longer synthesizes the new constructor.
For such cases, the compiler synthesizes the default constructor or inserts code into an existing default constructor in the sense that the base class child object of the class is initialized.
4. Class with virtual function
This situation means that the class declares or inherits one or more virtual functions.
For example, for the following code:
Class x{public : virtual ~x () { cout << "x::~x ()" << Endl; } virtual void print () { cout << "X::p rint ()" << Endl; } int mdata;}; Class Xx:public x{public : virtual ~xx () { cout << "xx::~xx ()" << Endl; } virtual void print () { cout << "XX::p rint ()" << Endl; } int MN;}; int main () { X *x = new XX; X->print (); Delete x;
class X has a virtual function print and a virtual destructor that run as follows:
It can be seen from the running result that the print function is called with the pointer of x, the print function of Class xx is called, and the destructor of Class xx is called when the delete is destructor, and then the derived class is first refactored into a destructor base class.
Therefore, because of the addition of virtual functions, the compiler will perform the following actions during compilation to make the virtual function mechanism work:
1) The Virtual function table (VTBL) is generated by the compiler and is used to store the virtual function address of the class.
2) Within the object of each class, an additional pointer member is synthesized by the compiler, which is a pointer to the virtual function table (vptr).
In addition, the compiler overwrites calls to virtual functions. For example, the main function above may be rewritten as the following pseudo-code
int main () { X *x = malloc (sizeof (XX)); X->vptr = xx::vtbl; (X->vptr[1]) (x); 1 is the index of the print function in Vtbl (X->vptr[0] (x);//0 is the index of the destructor in VTBL free (x);
Therefore, the default constructor for the compiler composition will put a vptr for the class and specify its initial value to point to the virtual function table of the class. If the class already has a constructor defined, the compiler will code each constructor to do the same thing (that is, the vptr is inserted and the initial value is set).
For such cases, the compiler synthesizes the default constructor or inserts code into an existing default constructor in the sense that the virtual function mechanism (polymorphic) can take effect correctly.
5. Class with a virtual base class This situation refers to a class that derives from an inherited chain of strings, which has one or more virtual base classes.
The implementation of the virtual base class differs greatly from one compiler to another, but the common denominator of each implementation is that the virtual base class must be positioned in each of its derived class objects to be ready during execution.
For example, for the following code (not well-designed code):
Class x{public : X () {mdata =;} int mdata;}; Class X1:virtual public x{public : X1 () {mX1 = 101;} int mX1;}; Class X2:virtual public x{public : X2 () {mX2 = 102;} int mX2;}; Class Xx:public X1, public x2{public : XX () {MXX = 103;} int MXX;}; int main () { cout << sizeof (XX): "<< sizeof (XX) << Endl; xx xx; int *p = (int*) &xx; for (int i = 0; i < sizeof (XX)/sizeof (int); ++i, ++p) { cout << *p << endl; } return 0;}
The contents of the object are traversed and output in the main function, and the result is as follows:
As you can see from the results, that the virtual function is not defined in all classes, the compiler still inserts two vptr for the subclass XX, where the first vptr belongs to X1 and the second vptr belongs to X2. As to what it does, I'm not sure, but it's certain that the compiler will have the necessary code for our defined constructors to implement the virtual base class mechanism. If the class does not declare any constructors, the compiler must synthesize a default constructor to complete the same operation.
Note: The virtual function in destructors Class X will also have a x::vptr placed before 100, that is, before the member variable of the base class X.
6. Summary
a class that satisfies one or more of the above 4 cases, and if no constructor is declared, the compiler will synthesize a default constructor for it, and if one or more constructors are declared, the compiler will have some code for each constructor to complete the necessary work. These synthesized constructors are referred to as implicit nontrivial default constructors (an implicit, valid defaults constructor).
A class that does not meet the above 4 cases, without declaring any constructors, has the implicit trivial default constructors (the implicitly invalid defaults constructor), which is not actually synthesized.
The resultant default constructor will only initialize the base class sub-objects and member class objects, and the other non-static member variables will not be initialized.
In addition, there are two common misconceptions about C + +:
1) Any class that does not have a default constructor defined will be synthesized.
2) The default constructor for the compiler composition, which explicitly sets the default value for each member data within class.
Construction of the default constructor for the C + + object model