|Ned Batchelder : Blog | Code | Text | Site|
More C++ constructor trivia
» Home : Blog : May 2005
Back in December, I wrote about C++ constructor trivia. There, I said:
Joe Ganley wrote to point out that I had it wrong, and indeed I did. (I've used the linguist's convention of starring sentences that are incorrect, though they do it for grammatical incorrectness.)
The correct statement of C++ semantics is:
If you attempt to construct a Derived object, you will see this output:
Since the exception was thrown in the Derived constructor, the Derived destructor is not called. But destructors are called for each of the constructors that had completed (namely, Member1, Base2, and Base1).
C++ works very hard to keep track of exactly what class an object is. During the construction process, the class changes. When the Base1 constructor has finished, the object is a Base1. When the Base2 constructor has finished, it is also a Base2. By the time the Derived constructor is entered, it is considered a Derived, even though its constructor never finishes. This process of evolving the object up through its inheritance tree is the programming language equivalent of the now-discredited biological theory of recapitulation (famous for its tongue-twister slogan of Ontogeny recapitulates phylogeny).
During the destruction process, the whole thing happens in reverse. As each destructor finishes, the object changes classes reverting back to the mud from which it came.
C++ is very precise about the order of execution of all of these constructors. Base classes are constructed in the order they were declared, then members are constructed in the order they were declared. Destruction always happens in the reverse order.
By the way, this evolution of classes becomes even more important to understand when virtual function calls are considered. Exactly which function gets called for a virtual function depends on the class of the object. But the class is changing as the object is constructed and destructed. Calling virtual functions from constructors and destructors can be complicated because of this.
One last twist: if you declare a virtual pure method (with the horrid "= 0" syntax), you create a class which cannot be instantiated. So you'd think there would be no way to call the pure virtual. But think about the recapitulation of classes again. While an object is being constructed or destructed, it passes through those abstract classes. If one of those virtual functions is called when the object belongs to an abstract class, you will get the dreaded "pure virtual function call" error!
tagged: c++» 3 reactions