C + + object model--default constructor construction operations (chap. II)

Source: Internet
Author: User

2nd. The semantics of Constructor on C + +, one of the most common complaints is that the compiler does too much with the programmer behind it. The conversion operator is one of the most frequently cited examples.
2.1 Default Constructor Construction Operations C + + annotated Reference Manual (ARM) pointed out "default constructors ... Generated by the compiler when needed. "The key word is "when you need it". Who needs it? Take a look at the following program code:
Class Foo {public:    int val;    Foo *pnext;}; void Foo_bar () {    foo bar;    if (Bar.val | | bar.pnext)        //... do something}
In this case, the correct program semantics is to ask Foo to have a default constructor, which can initialize its two members to 0, which does not conform to arm's "when needed". The difference is that one is the need for a program, One is the need of the compiler. The code above does not synthesize a default constructor.
SoWhen will a default constructor be synthesized? When the compiler needs it! In addition, the synthesized constructor only executes the actions required by the compiler ., that is, even if it is necessary to synthesize a default constructor for class Foo, that constructor will not initialize two data members Val and Pnext to 0. To make the last piece of code execute correctly, class The designer of Foo must provide an explicit default constructor that initializes the two members appropriately.
The C + + standard has modified arm's claim, although its behavior is actually still the same. C + + standard states that "for class X, if there is no user-declared constructor, then a default constructor is implicitly declared .... An implicitly-declared default constructor will be a trivial constructor ... "
Member class Object with default constructor if a class does not have any constructor, but it contains a member Object, the latter has the default constructor, Then this class implicit default constructor is "nontrivial", the compiler needs to synthesize a default constructor for this class, However, this synthetic operation only occurs when the constructor really needs to be called.
So there's an interesting question: In the different compilation modules of C + +, how the compiler avoids synthesizing multiple default constructor(for example, one is for A.C file synthesis, the other for B.C file synthesis)? The solution is to put the synthesized default constructor,copy constructor,destructor,assignment copy Operator are all done inline. An inline function has a static link (static linkage) and is not visible to anyone other than the file. If the function is too complex to fit inline, a explicit is synthesized non-inline The static entity.
For example, in the following program fragment, the compiler synthesizes a default constructor for class bar:
class Foo {public:    foo ();    Foo (int) ...    }; Class Bar {public:    foo foo;    char *str;}; void Foo_bar () {    bar bar;    Bar::foo the                //bar::foo is a member object that must be initialized here. and its class Foo has defautl constructor    if (str) {        ...    }};
The synthesized bar default constructor contains the necessary code to invoke the default constructor of class Foo to handle the member object Bar::foo, but it does not produce any code to initialize Bar:: Str. Initializing Bar::foo is the responsibility of the compiler, it is the responsibility of the programmer to initialize BAR::STR, and the synthesized default constructor may be as follows:
Bar's default constructor may be synthesized in this way//by member Foo calling the default Constructorinline of Class Foo Bar::bar () {    //C + + pseudo code    foo . Foo::foo ();}

Note that the synthesized default constructor only satisfies the needs of the compiler, not the needs of the program, and in order for the program fragment to execute correctly, the character pointer str needs to be initialized. Suppose the programmer passes the following default Constructor provides the init operation of STR:
Programmer-Defined default Constructorbar::bar () {str = 0;}
The requirements for the program are now met, but the compiler also needs to initialize the Member object foo. Because the default constructor has been explicitly defined, the compiler has no way to synthesize the second one.
The compiler takes action: If Class A contains one or more member class objects, then each constructor of class A must invoke the default classes for each member constructor, The compiler expands the existing constructors, placing some code in it so that the user code will invoke the necessary default constructors before it is executed. Along the previous example, the expanded constructors might look like this:
The expanded default constructor//C + + pseudo code Bar::bar () {    foo. Foo::foo ();    Append on complier code    str = 0;        Explicit user Code}
If there are multiple class member objects require constructor initialization operation, how would it be?The C + + language requires "Member objects in class declaration order" to invoke each constructorsThis is done by the compiler, which constructor the program code for each one and invokes the default constructor associated with each member in the member declaration order. These codes are placed in the explicit user Code before. If there are three classes as follows:
Class Dopey {public:    Dopey ();}; Class Sneezy {public:    sneezy (int);    Sneezy ();}; Class Bashful {public:    bashful ();};    and a class Snow_white:class Snow_white {public:    Dopey Dopey;    Sneezy Sneezy;    Bashful bashful;private:    int number;};
If Snow_white does not define the default constructor, a nontrivial constructor is synthesized, sequentially invoking the default of dopey, Sneezy, and bashful Constructor However, if Snow_white defines a default constructor such as the following:
The programmer writes the default constructorsnow_white::snow_white (): Sneezy (1024x768) {    member = 2048;}    It will be expanded to://compiler expanded default constructor//C + + pseudo Code snow_white::snow_white (): Sneezy (1024x768) {    //Insert Member class object    //Call its constructor    dopey. Dopey::D opey ();    Sneezy. Sneezy::sneezy (1024x768);    Bashful. Bashful::bashful ();    Explicit user mode    member = 2048;}
The sequence is the member object of the class, and the constructor for the class.
Base class with default Constructor if a class without any constructors is derived from a base class with default Constructor, then this derived Class's default constructor is considered nontrivial and therefore needs to be synthesized, it calls the default constructor of the base classes on the previous layer (according to their Order of declaration), to a subsequent derived Class, there is no difference between this synthetic constructor and a "explicitly provided default constructor".
If the designer provides multiple constructor, but none of them has the default constructor? The compiler expands each of the existing constructor, adding the program code "to invoke all necessary default constructors" , it does not synthesize a new default constructor, because the other "constructor provided by user" exists. If the Member class objects with default constructors are present, those default constructor will also be called after all base class constructor have been called. Can be seen, constructs start at the root of the class hierarchy, and at each level, the base class constructor is called first, and then the constructor of the member object is called
The class "with one virtual Function" has two other cases, and it needs to synthesize the default constructor:
1. class declaration (or inheritance) a virtual function
2. Class derives from an inherited string chain, which has one or more virtual base classes.
In either case, due to the lack of a user-declared constructors, the compiler will detail the necessary information to synthesize a default constructor, as an example of this program fragment:
Class Widget {public:    virtual void flip () = 0;    // ...}; void Flip (const Widget &widget) {    widget.flip ();} Suppose both Bell and whistle derive from Widgetvoid foo () {    bell B;    Whistle W;    Flip (b);    Flip (w);}
The following two expansions occur during compilation:
1. A virtual function table (known as VTBL in Cfront) is generated by the compiler, with the virtual functions address of class.
2. In each class object, an additional pointer member (that is, vptr) is synthesized by the compiler, containing the address of the associated class VTBL.
In addition, virtual invocation of the Widget.flip () will be rewritten to use the flip () entry in the widget's vptr and VTBL:
Widget.flip () (Virtual invocation) transformation (*widget.vptr[1]) (&widget)
which
1 indicates the fixed index of flip () in virtual table
The &widget represents the this pointer to the called Flip () function entity.
In order for this mechanism to function, The compiler must set an initial value for the vptr of each widget (or its derived class) object and place the appropriate virtual table address. For every constructor defined by class, the compiler will have some code to do something like this.(see section 5.2). For those classes that do not declare any constructor, the compiler will synthesize a default constructor for them so that the vptr of each class object is initialized correctly.
The implementation of the class virtual base class with a virtual base class has a great difference between the different compilers, however, the common point of each implementation is that the virtual base class must be positioned in each of its derived class object to be ready for the execution period, such as in the following code:
Class X {public:    int i;}; Class A:public virtual X {public:    int J;}; Class B:public virtual X {public:    double D;}; Class C:public A, public B {public:    int k;};/ /Unable to determine (resolve) the location of the pa->x::i at compile time void foo (const A *pa) {    pa->i = 1024;} Main () {    foo (new A);    Foo (new C);    // ...}
The compiler cannot determine the actual offset of "x::i accessed through Pa" in Foo () because the true type of PA can be changed.The compiler must change the code of the "Execute access operation" so that the x::i can be deferred to the execution period before deciding。 The original Cfront was done by placing a pointer in each virtual base classes of the derived class object. All operations that "access a virtual base class via reference or pointer" can be done through the relevant pointers. Foo can be rewritten as follows to conform to this implementation strategy:
possible compiler conversion operation void foo (const A *pa) {    pa->_vbcx->i = 1024;}
Where _VBCX represents a pointer produced by the compiler, pointing to virtual base class X.
_VBCX (or something that the compiler makes) is done during class object construction. For each constructor defined by class, the compiler will insert the code that "allows the execution of each virtual base class to access operations." If class does not declare any constructor, the compiler must synthesize a default constructor for it.
There are four scenarios in which the compiler must synthesize a default constructor ' for classes that are not declared constructor, and C + + Stardard call those compounds implicit nontrivial default Constructor The synthesized constructor only satisfies the needs of the compiler (not the program). It is able to accomplish its task by "invoking the default constructor of member object or base class" or "initializing its virtual function mechanism or virtual base for each object" Class mechanism "to complete. As for the absence of those four cases without declaring any constructor classes, they have implicit trivial default constructor, which are not actually synthesized.
In the synthesized default constructor, only the base class subjects and member class objects are initialized, and all other nonstatic data member, such as integers, integer pointers, Integer data, and so on, are not initialized, which may be necessary for the program, but not necessarily for the compiler. If the program requires a default constructor that "sets a pointer to 0", it should be a programmer.
C + + newbies generally have two common misconceptions:
1. If the default constructor is not defined for any class, it will be synthesized.
2. The default constructor compiled by the compiler will explicitly set the "class with each of the data member defaults"
Both of these are wrong.


Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

C + + object model--default constructor construction operations (chap. II)

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.