Construction operations of default constructor in the C ++ object model, and object model constructor

Source: Internet
Author: User

Construction operations of default constructor in the C ++ object model, and object model constructor
A class. If there is no user-declared constructor, a default constructor is implicitly declared. The implicitly declared constructor determines when the default constructor is merged by the compiler and how the compiler processes user-defined constructor, this is the question to be discussed in this article.

1. When the default constructor is merged
If a class does not have any user-declared constructor, the compiler will synthesize a default constructor for the class when the compiler needs it, it is only used to execute the operations required by the compiler. Note that the default constructor is synthesized when the compiler needs it, rather than when the program needs it. If the program needs it, the default constructor should be implemented by the programmer.

When does the compiler need it? Correctly, the compiler needs to synthesize a default constructor for the following four types of classes:
1) The member variables of the class carry the default constructor
2) The base class of the class has the default constructor
3) class with virtual functions
4) the class has a virtual base class.
The merging operation is merged only when the constructor needs to be called.

Another problem is that in C ++, how can the compiler avoid merging multiple default values? The solution is to merge the default constructor, copy constructor, destructor, and value assignment operator in the form of inline. If the function is too complex to be made into inline, it will become an explicit non-inline static function. Whether it is an inline or a non-inline static function, it is used to avoid being accessed by others.

For the following program:

class X{    public:        int mData;        int *mPtr;}; 

Class X does not declare any constructor, but it does not belong to the four types mentioned above. Therefore, the compiler does not synthesize a default constructor for class X.

The following describes the behavior of the default constructor synthesized by the compiler for the preceding four types of classes.
2. The member variables of the class carry the default constructor (that is, the class contains the member class Object (member class objects ))
In this case, a class does not have any constructor, but its member variables are the variables of a class with 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;    return 0;} 

Class Xs does not define any constructor, but its member variable mX is of Type X and Class X has a default constructor. The running result is as follows:


From the running results, we can see that in the default constructor synthesized by the compiler for the class Xs, the constructor of X is called to initialize the member variable mX, however, the default constructor of the synthesis does not initialize the member variable mN of the class Xs. It can be seen that the constructor of the Compiler class Xs is as follows:
inline Xs::Xs(){    mX.X::X();}

Sometimes we define a default constructor for the class. But in this constructor, only some member variables are initialized. What kind of behavior and effect will happen? Keep the test code of Class X and main functions unchanged. modify the code of class Xs as follows:
class Xs{    public:        Xs()        {            cout << "Xs::Xs()" << endl;            mN = 1;        }        X mX;        int mN;}; 

We can see that we have added a default constructor for the class Xs, but in this constructor, we only initialize the member variable mN. The running result is as follows:


The running results show that, although mX is not explicitly initialized in the default constructor of class Xs, the default constructor of Class X is still called, the Calling sequence is still in front of the default constructor code of the class Xs.

It can be seen that the behavior of the compiler is: if the class contains one or more class member objects ), therefore, each constructor of this class must call the default constructor of each class member (in the order declared by the members ). The compiler expands the existing constructor and inserts some code into it to call the default constructor of necessary class members before the user's code is executed.

The Xs constructor can be represented by the following pseudocode:
inline Xs::Xs(){    mX.X::X();    cout << "Xs::Xs()" << endl;    mN = 1;} 

In this case, the compiler combines the default constructor or inserts code into the existing default constructor to initialize each class member variable.
3. The base class of the class has the default constructor
In this case, a class without any constructor is derived from a class with the 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 constructor, but its base class X has a default constructor. The running result is as follows:


From the running results, we can see that the constructor synthesized by the compiler calls the default constructor of the previous base class. For a subsequent derived class, the default constructor of this synthesis is no different from the default constructor provided explicitly.

If the class designer provides one or more Constructors (including Default constructors), but the constructors provided by the class do not explicitly call their base class constructors, what will the compiler do?

Add two constructors to class XX and modify the test code of the main function, as shown below:
class XX : public X{    public:        XX()        {            mN = 1;        }        XX(int n)        {            mN = n;        }        int mN;};int main(){    XX xx1;    XX xx2(2);    return 0;} 

Constructor of class XX does not explicitly call the constructor of its base class. The running result is as follows:


The running results show that the compiler expands every present constructor of the derived class and inserts all the necessary default constructor code to be called. Note: Since User-Defined constructor already exists, the compiler does not synthesize new constructor.

In this case, the compiler combines the default constructor or inserts code into the existing default constructor to ensure that the base class sub-objects of the class are initialized.

4. classes with virtual functions
In this case, 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::print()" << endl;        }        int mData;};class XX : public X{    public:        virtual ~XX()        {            cout << "XX::~XX()" << endl;        }        virtual void print()        {            cout << "XX::print()" << endl;        }        int mN;};int main(){    X *x = new XX;    x->print();    delete x;    return 0;} 

Class X has a virtual function print and a virtual destructor. The running result is as follows:

From the running results, we can see that the print function is called using the X pointer, and the print function class XX is called, and the delete destructor is also called, first, the derived class and then the base class.

Therefore, due to the addition of virtual functions, the compiler will perform the following operations during compilation to enable the virtual function mechanism to play a role:
1) virtual function tables (vtbl) are generated by the compiler and stored as virtual function addresses of classes.
2) in each class object, an extra pointer member will be synthesized by the compiler. This pointer is the pointer to the virtual function table (vptr ).

In addition, the compiler will rewrite the call of virtual functions. For example, the above main function may be rewritten into 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 ); return 0 ;}

Therefore, the default constructor synthesized by the compiler inserts a vptr for the class and specifies its initial value so that it points to the virtual function table of the class. If the constructor has been defined for this class, the compiler will install the same code for each Constructor (that is, install vptr and set the initial value ).

In this case, the compiler combines the default constructor or inserts code into the existing default constructor to make the virtual function mechanism (polymorphism) take effect correctly.

5. A class has a virtual base class. In this case, the class is derived from an inherited string, with one or more virtual base classes.

The implementation methods of the virtual base class vary greatly across different compilers. However, the commonality of each implementation is that the location of the virtual base class in each of its derived class objects must be, can be properly prepared during execution.

For example, for the following code (not well-designed code ):
class X{    public:        X() {mData = 100;}        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 main function traverses and outputs the object content. The running result is as follows:


From the results, we can see that, like no virtual function is defined in all classes, the compiler still inserts two vptr for the subclass XX, where the first vptr belongs to X1, the second vptr belongs to X2. I still don't know how it works, but it is certain that the compiler will install the necessary code for our defined constructor to implement the virtual base class mechanism. If the class does not declare any constructor, the compiler must synthesize a default constructor to complete the same operation.

Note: If the base class X contains a virtual function, an X: vptr is inserted before 100, that is, before the member variable of the base class X.

6. Summary
If one or more of the above four situations is met, the compiler will synthesize a default constructor if no constructor is declared. If one or more constructor is declared, the compiler inserts a certain amount of code into each constructor to compile the necessary work. These constructor functions are called implicit nontrivial default constructors (which is an implicit valid default constructor ).

If no constructor is declared for a class that does not meet the preceding four conditions, the class has implicit trivial default constructors (default conors ors that are implicitly invalid) and will not actually be merged.

The synthesized default constructor will only initialize the base class sub-objects and member class objects. Other non-static member variables will not be initialized.

In addition, C ++ has two common misunderstandings:
1) if no default constructor is defined for any class, it will be merged.
2) The default constructor synthesized by the compiler explicitly sets the default value for each member data in the class.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.