Abstract: constructor and destructor in C ++ avoid calling virtual functions.

Source: Internet
Author: User

Http://anwj336.blog.163.com/blog/static/8941520920106791516915/

1. constructor to avoid calling virtual functions

Although calling a virtual member function in constructor is not a very common technique, studying it can deepen the understanding of the virtual function mechanism and object construction process. This problem is also different from the general intuitive understanding. Let's take a look at the two class definitions below.

Struct C180
{
C180 (){
Foo ();
This-> foo ();
}
Virtual foo (){
Cout <"<C180.foo this:" <this <"vtadr:" <* (void **) this <endl;
}
};
Struct C190: public C180
{
C190 (){}
Virtual foo (){
Cout <"<C190.foo this:" <this <"vtadr:" <* (void **) this <endl;
}
};

The parent class has a virtual function, and the parent class calls this virtual function in its constructor.When calling, it uses two methods: one is direct call, and the other is throughThisPointer call.At the same time, the subclass overrides this virtual function.

We can predict what will happen if a C190 object is constructed.

We know that when constructing an object,The process is as follows:
1)First, a memory block is obtained based on the object size.(InHeapUp or inStackUpper),
2)Use the pointer pointing to this memoryThisPointer to call the class constructor and initialize the memory.
3)If the object has a parent class, the constructor of the parent class will be called first.(And recursion in turn)If there are multiple parent classes(Multi-Inheritance)The constructor of the parent class is called in sequence and adjusted as appropriate.ThisPointer position.
After calling the constructor of all parent classes, execute your own code.

When C190 is constructed according to the above analysis, the C180 constructor will also be called.OneFooCall static binding,Will callC180: foo ()Function.
TheTwoFooThe call is called through a pointer. In this case, the multi-state behavior will occur. What should be called?C190: foo ()Function.

Run the following code:

C190 obj;
Obj. foo ();

Result:

<C180.foo this: 0012F7A4 vtadr: 0045C404
<C180.foo this: 0012F7A4 vtadr: 0045C404
<C190.foo this: 0012F7A4 vtadr: 0045C400

This is quite different from our analysis.The first line is inC180RunningFoo ()Function.Foo ()Of course it is calledC180InFoo ()Function.
The second line is the callC190InThis-> foo ()In this caseThisIt should pointC190According to the calling rules, the virtual table address of the derived class should be dynamically bound. That is, if the derived class has implemented the virtual function, the virtual function of the derived class should be called.Here is an exception, which will be detailed below. So far, the constructor of the parent class of C190 has finished running, and then runs the constructor of C190, but here there is nothing in the constructor of C190. The third line is obtained by calling obj. foo () in the main function. You can directly run it in C190. Note that the virtual tables of the first two rows and the third row are different, because the virtual tables of the first two rows are virtual tables of C180, the virtual table in the third row is the virtual table in C190. In fact, this is exactly the secret.

For this reason, I checked the C ++ Standard Specification.In12.7.3There are clear provisions. This is a special case. In this case, the constructor of the parent class is called when the child class is constructed, and the constructor of the parent class calls the virtual member function, this virtual member function does not allow polymorphism even if it is overwritten by the quilt class. That is, you must call the virtual
Function, rather than the virtual function after the subclass is overwritten.

The reason for this is thatWhen the constructor of the parent class is used, the member variables in the object that belong to the subclass must not be initialized, because the code in the subclass constructor has not been executed yet. If polymorphism is allowed at this time, that is, the virtual function of the subclass is called through the constructor of the parent class, and this virtual function may fail to access data members of the subclass.

2. Why can't constructors call virtual functions?

First,In terms of concept, the function of constructor is to convert an object into an existing object. In Any constructor, objects may only be partially formed.-We can only know that the base class has been initialized, but we do not know which class is inherited from this base class.However,The virtual function is"Forward"And"Outward". It can call functions in a derived class. If we do the same in the constructor, the function we call may not be initialized, which will lead to a disaster.
Second, when a constructor is called,One of its first tasks is to initialize it.VPTR. Therefore,It can only know that it is"Current"Class, while ignoring whether there are successors behind this object. When the compiler generates code for this constructor, it generates code for the constructor of this class-neither the base class nor, it is not a derived class for it (because the class does not know who inherits it ).
So it usesVPTRMust be for this classVTABLE. In addition, as long as it is the final constructor call, the VPTR will be initialized to point to this VTABLE during the lifetime of this object. However, if another later-derived constructor is called, the constructor sets VPTR to point to its VTABLE until the final constructor ends.VPTRThe status is determined by the final called constructor. This is another reason why constructor calls are ordered from the base class to a more derived class.
However, when this series of constructor calls occur,Each constructor has been setVPTRPoint to its ownVTABLE. If a function call uses a virtual mechanism, it will only generateVTABLEInstead of callingVTABLE(ALL constructors are called before they end.VTABLE).
In addition, many compilers realize that early bundling should be used for virtual function calls in constructors, because they know that late bundling will only generate calls to local functions. In either case, no result is returned when a virtual function is called in the constructor.
Therefore, constructor cannot be virtual. However, it is often used for destructor, and preferably virtual! This is not negotiable for the time being ..

Iii. Calling virtual functions in destructor

The same logic exists in the object structure.Once the destructor of a derived class runs, the data member of the derived class of this object is assumed to be an undefined value,C ++They are treated as non-existent. Once you enter the destructor of the base class, the object becomes a base class object,C ++(Virtual function,Dynamic_castOperators.Dynamic_castThere is only a security check, and the subclass cannot be forced to become the parent 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.