Software Engineering and Computer Games
Authors: Rucker R.
Published year: 2002
Pages: 173-174/272
Buy this book on amazon.com >>

22.9 Parent and child constructors and destructors

When a class object is constructed , the following sequence takes place.

  1. Memory storage for the object is allocated (e.g. enough bytes for the object's data fields are allocated in memory).

  2. The default constructor of the parent class (if any) is called, unless you explicitly request some other parent constructor in your initializer list.

  3. The constructors for each of the class member objects are executed (in the order of the member classes' declaration); if there is no initializer list the default constructors are called, but you can request special constructors in your initializer list.

  4. The class constructor code is executed.

When a class object is destroyed the following sequence takes place.

  1. The class destructor code is called.

  2. The destructor of each of the class member objects is executed.

  3. The destructor of the base class (if any) is executed.

  4. The memory storage for the object is recycled.

So the cMyChild constructor automatically calls the default cMyParent constructor before getting inside its own code. A handy way to think of this is to imagine that a cMyChild object has a cMyParent object as a member. The parent class and the members all get their constructors called.

Now, it may be that you want to feed some arguments into the base class or member constructors. To do this, you write out these constructors in an 'initializer list' that follows a colon after the constructor. Here's an example of a class definition.

cTeacherProgrammer : public cProgrammer 
{ 
private: 
    int _ugliness; 
    cGollywog *_pimaginaryfriend; 
public: 
    cTeacherProgrammer(int flubba, float gleep); 
    ~cTeacherProgrammer(); 
}

And here's a constructor using an initializer list.

cTeacherProgrammer::cTeacherProgrammer(int flubba, float gleep): 
    cProgrammer(flubba, gleep), 
    _ugliness(1000000) 
{ 
    _pimaginaryfriend = new cGollywog(this); 
}

And here's how the destructor would be defined.

cTeacherProgrammer::~cTeacherProgrammer(){delete _pimaginaryfriend);}

Note that the cTeacherProgrammer destructor first does the delete _pimagi naryfriend , and then calls the parent cProgrammer destructor. You can remember the sequence by thinking in terms of working your way down the hierarchy at construction, and working your way back up at destruction.

When you need to code up several different forms of a constructor, it can be useful to have an initialization helper function that the different constructors in both the parent and the child class can call.


22.10 Virtual methods

The keyword virtual in front of a parent class method tells the C++ compiler that the class has a child class which has a method which has the same name but which acts differently in the child class. If (a) a method is declared as virtual , and (b) the object which calls the method is referred to via a pointer, then (c) the compiled program will, even while it is running, be able to decide which implementation of the virtual method to use. It is worth stressing that this 'runtime binding' only works if you the programmer fulfill both conditions: (a) you use virtual in your method declaration, and (b) you use a pointer to your object.

Except in the case of a destructor, corresponding virtual functions have the same name. You don't put the word virtual in front of the actual function implementation code in the *.cpp . You can put virtual in front of the child class function declaration in the child class's header file or not, as you like. In other words, to start with, you really only need to put virtual in one place: in front of the parent class's declaration of the function.

But, in order to make our code more readable, when we derive off child classes from a parent class with a virtual function, we usually do put virtual in front of the child method declaration as well as in the parent method declaration. The child does need to have a declaration for the method in order to override it in any case.

One slightly weird thing is that a parent class destructor like ~cProgrammer() needs to be declared virtual even though a child class destructor like ~cTeacherProgrammer() seems to have a different name. But you don't in fact call the destructor by name. In a program where we have a cProgrammer *_ptextbookauthor , we might be calling either the cProgrammer or the cTeacher destructor with a line like delete _ptextbookauthor; . The thing is, it's possible that _ptextbookauthor got initialized as new cTeacher , so we just don't know.

The delete operator calls the destructor without referring to the destructor method by name. So the compiled code needs to actually look at the type of the _textbookauthor pointer to find out whether it's really a cProgrammer * or a cTeacherProgrammer* , so it knows which destructor to use. And unless you fulfilled the 'virtual condition' by making the destructor virtual , then the code won't know to do runtime binding and choose between using the parent or the child method as appropriate. The destructors are different here because the cTeacherProgrammer has more stuff to destroy, in particular, the cGollywog *_pimaginaryfriend .

Slogan for a class: If your child is richer than you, you need a virtual destructor .

One final point should be mentioned here. Ordinarily, when you have a method virtual void somemethod() in a base class called, say, cParentClass , then when you override the method in a child class called, say, cChildClass , the child class somemethod() will call the parent class method if we explicitly ask it to with code like this.

void cChildClass::somemethod() 
{ 
    cParentClass::somemethod(); 
    //Your extra childclass code goes here.... 
}

But in the case of a virtual destructor, the parent class's destructor method will be automatically called when the object is deleted. This is in accord with the standard C++ execution order of constructors and destructors mentioned in the last subsection.

cChildClass::~cChildClass() 
{ 
    //Your extra child class destructor code goes here... 
... 
    /* The cParentClass::~cParentClass destructor will be 
        automatically called 
        here at the end of the ~cChildClass destructor call. */ 
}
Software Engineering and Computer Games
Authors: Rucker R.
Published year: 2002
Pages: 173-174/272
Buy this book on amazon.com >>

Similar books