Call of constructor and destructor in class inheritance
Currently, there are three classes. The class definition is as follows:
Class ca
{
Public:
CA () {cout <"ca constructor" <Endl ;}
~ CA () {cout <"ca desstructor" <Endl ;}
};
Class CB: public CA
{
Public:
CB () {cout <"CB constructor" <Endl ;}
~ CB () {cout <"CB desstructor" <Endl ;}
};
Class CC: Public CB
{
Public:
CC () {cout <"cc constructor" <Endl ;}
~ CC () {cout <"cc desstructor" <Endl ;}
};
Ca is grandpa, CB is father, and CC is son.
In any c ++ book, The Calling sequence of constructor is ca cb cc, and the calling sequence of destructor is CC, CB, Ca. What ??? You didn't talk about your book. You can leave it alone.
Therefore
(1) int main ()
{
Cc p;
}
The program running result is
CA Constructor
CB Constructor
CC Constructor
CC desstructor
CB desstructor
CA desstructor
It's too easy. An egg flew over ,:(
Continue ........................
(2) Before the second test, make a small modification.
~ CA () {cout <"ca desstructor" <Endl ;}----- >>>
Virtual ~ CA () {cout <"ca desstructor" <Endl ;}
Modify the main Code as follows:
Int main ()
{
Ca * P = new CC ();
Delete P;
Return 0;
}
Yeah
The results are exactly the same.
CA Constructor
CB Constructor
CC Constructor
CC desstructor
CB desstructor
CA desstructor
However ~ CA () {cout <"ca desstructor" <Endl ;}
Remove virtual from
Then the running result in (2) is
CA Constructor
CB Constructor
CC Constructor
CA desstructor
I only called the CA.
In this case, the base class constructor is called, but the constructor of the derived class is not called,
The derived part of the object is not destroyed, which causes resource leakage.
So when we design a class, if the class has at least one virtual function, or the base class is designed for polymorphism, in this case,
The object of a derived class may be operated by a base class pointer and then destroyed. If so, the destructor of this base class should be set to virtual,
Although some classes are base classes, they are not used for polymorphism. They do not have virtual functions and are not designed to allow operations on the objects of derived classes through the base class interfaces. Therefore, you do not need to set them to virtual destructor, after all, it increases the overhead,
Okay, I have explained it clearly. We also know how to do it and continue the experiment.
(3)
Reserve virtual destructor in CA
Modify the main Code as follows:
Int main ()
{
CB * P = new CC ();
Delete P;
Return 0;
}
Running result
CA Constructor
CB Constructor
CC Constructor
CC desstructor
CB desstructor
CA desstructor
Cancel the virtual destructor in CA, so there is no virtual destructor in CA, CB, and CC.
The code running result in step 3 is as follows:
CA Constructor
CB Constructor
CC Constructor
CB desstructor
CA desstructor
Only the analysis structure of CB is adjusted,
Continue the test. In Ca, CB, and CC, only CB is a virtual destructor.
3. Run the following code:
CA Constructor
CB Constructor
CC Constructor
CC desstructor
CB desstructor
CA desstructor
Therefore, if CB points to a derived class, as long as Cb or its base class has a virtual destructor, all the Destructor are called.
Continue ..................
(4)
Modify the main Code as follows:
Int main ()
{
Ca * P = new CC ();
Delete P;
Return 0;
}
If the destructor of A is virtual, the situation is as follows: 2.
If the CA destructor are not virtual, And the CB or CC destructor are virtual, a memory error occurs when you call Delete P;
Expression: _ block_type_is_valid (phead-> nblockuse)
This error occurs when the memory is released.
Check the Internet. _ block_type_is_valid is one of the macros used to check the memory validity. This error indicates that the pointer is faulty.
Later I thought about it. It should be because of the appearance of virtual functions in the inheritance class, so I added a pointer to the virtual function table, and none of the base classes had a virtual function, so there is no such pointer.
Therefore, a memory error occurs during the delete operation. As it turns out, this conjecture should be valid. Add a virtual function to the CA, even if it is an empty virtual function, there will be no memory errors,
For this question, I want to continue the discussion next time. I will not go into details here,
Return to the topic and add an empty, arbitrary virtual function to the CA to run correctly,
The running result is
CA Constructor
CB Constructor
CC Constructor
CA desstructor
This is the same as in (2). As long as the CA destructor is not virtual, you can only call the CA destructor.
Finally, let's look at a very BT approach.
(5)
It doesn't matter who is a virtual destructor in ca cb cc.
Modify the main Code as follows:
Int main ()
{
Void * P = new CC ();
Delete P;
Return 0;
}
Running result
CA Constructor
CB Constructor
CC Constructor
What about the following ??? No more. Dizzy ........................
In this case, a CC object is constructed, and the requested memory is directly released without the destructor. It is best not to use it like this.
Okay. At last, we sorted out all the situations that I could think,
To sum up
For example
C1 * P = new C2 ();
Delete P;
Such code
Here, C1 is the base class of C2. C1 may be the father of C2, grandpa, or Grandpa of C2, it may be grandpa's grandfather ..............................
First, the called constructor is
From the first ancestor of C2 to C2 ................... It's okay with C1.
When deleting P, there are the following situations:
1) if the ancestor (base class) of C1 or C1 contains a virtual destructor, the sequence of the called destructor is the first ancestor from C2 to C2.
2) If none of the ancestor C1 or C1 contains a virtual destructor, it calls the First Ancestor from C1 to C1 (which is also C2 ).
3) If C1 is void, no destructor will be called.
If a class is a base class of polymorphism, declare the Destructor as virtual. Otherwise ..................,
Reference books
Objective C ++