You are here:

C++/VIRTUAL Constructor & destructor

Advertisement


Question
Hi, can you please explain abt Virtual constructor and Virtual Destructors in C++.

Answer
Yes.

First C++ does not directly support such thing as a virtual constructor - more on this below.

Next let us review virtual functions in brief:

Virtual functions are the way C++ implements the object oriented idea of polymorphism.

Polymorphism has to do with treating objects of one type like another. Specifically the behaviour of objects.

In C++ the types have to be related in a base<-derived relationship (i.e. one type is derived from the other) and the objects in question have to be accessed via references or pointers (pointers by the way are really another sort of reference in the general sense - rather than the narrower C++ specific meaning of reference types).

Generally we pass around references (or pointers) to base types that refer (or point) to objects of the base of any type derived from the base type. If a member function declared as virtual in the base class is implemented in a derived class then we say the virtual member function is 'overridden' and calling the member function through a reference (or pointer) to a base object that refers to an instance of a derived class then the derived implementation is called, thus:
   // In header file virtual_example.h

   class Base
   {
   public:
       virtual void OverrideThisFunction();
   };

   class Derived : public Base
   {
   public:
       void OverrideThisFunction();
   };


   // In implementation file

   #include "virtual_example.h"
   #include <iostream>

   void Base::OverrideThisFunction()
   {
       std::cout << "Base implementation called.\n";
   }

   void Derived::OverrideThisFunction()
   {
     std::cout << "Derived implementation called.\n";
   }

 
   // In main implementation file

   int main()
   {
       Base b;
       Derived d;

       b.OverrideThisFunction();
       d.OverrideThisFunction();

       Base * pB = &b;
       pB->OverrideThisFunction();

       pB = &d;
       pB->OverrideThisFunction();
   }
In the above very simple example I define two classes Base and Derived. Base declares a single public virtual member function OverrideThisFunction which is overridden by Derived. The implementations of OverrideThisFunction just output a line of text to the console stating which class' implementation has been called.

In main I create instances of Base and Derived types b and d respectively and call OverrideThisFunction on each. Next I create a pointer to base pB and initialise it with the value of the address of b and call OverrideThisFunction through pB. I then assign the value of the address of d - the Derived object to pB and again call OverrideThisFunction through pB.

The output should be something like so:

   Base implementation called.
   Derived implementation called.
   Base implementation called.
   Derived implementation called.

The important bit here is the final call to OverrideThisFunction. It is a virtual call - we call via a pointer to a Base object but get the behaviour of the actual Derived object pB points to.

OK so that is the 5 minute (well somewhat longer to type out) explanation of polymorphism and virtual member functions and member function overriding in C++ and hopefully mean we are both talking about the same thing. For more on polymorphism you could start with the Wikipedia article http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming.

So what are virtual destructors?

First let us revise what destructors are. Destructors are special class member functions that allow objects to clean up - releasing resources owned by objects of the type and the like - before the memory such objects occupy is released when the are destroyed.

Now this leads to a problem for objects that are used polymorphically. It is quite likely such objects will be destroyed through pointers or references to their base type. If this is done then the destructor called will be that of the base type and _not_ that of the derived type that is the type of the object actually referred to (or pointed to).

Expanding our example, say derived hold onto some resource - say it dynamically creates some other object and therefore requires a destructor to release it viz:

   class Base
   {
   public:
       virtual void OverrideThisFunction();

       ~Base(); // ## NEW ##
   };

   class Derived : public Base
   {
     int *  someStuff_; // ## NEW ##
   public:
       void OverrideThisFunction();

       Derived()
       : someStuff_( new int[100000] )  // ## NEW ##
       {
       }

       ~Derived(); // ## NEW ##
    };


   // In implementation file

   #include "virtual_example.h"
   #include <iostream>

   void Base::OverrideThisFunction()
   {
       std::cout << "Base implementation called.\n";
   }

   Base::~Base()   // ## NEW ##
   {
       std::cout << "Base destructor called.\n";
   }

   void Derived::OverrideThisFunction()
   {
     std::cout << "Derived implementation called.\n";
   }

   Derived::~Derived() // ## NEW ##
   {
       std::cout << "Derived destructor called. Releasing resources...\n    ";
       delete [] someStuff_;  // ## Release memory held for array allocated in constructor
   }

 
   // In main implementation file

   int main()  // ## NEW ##
   {
       Base * pB = new Base;
       pB->OverrideThisFunction();
       delete pB;

       Derived * pD = new Derived;
       pD->OverrideThisFunction();
       delete pD;

       pB = new Derived;
       pB->OverrideThisFunction();
       delete pB;        /// ### Oops calls Base::~Base not Derived::~Derived, 100000 ints not released!!!
   }

Here I have added destructors to both Base and Derived, and added a pointer to int member someStuff_ to Derived which I initialise to be an array of 100000 ints in the added Derived constructor. The Base destructor just announces its been called. The Derived destructor does this also but then cleans up by deleting the int array pointed to by the someStuff_ member.

In main I dynamically create objects, call the OverrideThisFunction on them and delete them. I do this for a Base object via a pointer to Base, a Derived object via a pointer to Derived and, crucially, a Derived object through a pointer to Base. The output should be as follows:

   Base implementation called.
   Base destructor called.
   Derived implementation called.
   Derived destructor called. Releasing resources...
       Base destructor called.
   Derived implementation called.
   Base destructor called.

Note that in the final case where we reference a Derived object through a Base pointer the Derived destructor is _not_ called and therefore we leak the memory used for the array allocated and pointed to by the Derived::someStuff_ member. [As an aside when the Derived destructor is called after doing its stuff a call is then made to its base part(s)' destructor(s) - Base::~Base in this case - so that it/they can do their clean up as well.]

The fix for these problems is simple - we make the Base destructor virtual:

   // In header file virtual_example.h

   class Base
   {
   public:
       virtual void OverrideThisFunction();

       virtual ~Base(); // ## Base destructor is now virtual ##
   };

Now if we look at the output:

   Base implementation called.
   Base destructor called.
   Derived implementation called.
   Derived destructor called. Releasing resources...
       Base destructor called.
   Derived implementation called.
   Derived destructor called. Releasing resources...
       Base destructor called.

We can see that the Derived destructor is now called even when we destroy a Derived object through a pointer (or reference) to Base.

The rule is that anytime you declare one or more virtual functions in a (base) class you should also declare the destructor virtual as well. Or to put in another way: any class designed to be derived from (which almost always means they will have virtual member functions) will require a virtual destructor.

Now onto virtual constructors and why there is no such thing.

In all the uses of polymorphism we have seen you require objects to start with - even if you then refer to them via some pointer or reference to a base type. When we create an object we have to know its _exact type_ - how else would a compiler know what to create otherwise. Saying I want something that is either a base type or something derived from it is far too vague. In C++ if you ask for an instance of type T then an instance of type T is _exactly_ what you get (unless for some reason such a request fails). When we create an object there is no existing object or reference/pointer to an object - or reference/pointer to a base object - we can use for a hint.

The following comes directly from an answer of mine to a previous question with a few tweaks (see http://en.allexperts.com/q/C-1040/constructor-virtual.htm for the original):

Constructors are always non-virtual and refer to the object type in which they are defined. By default a derived class instance will call its base classes' default constructors before it executes to ensure they are all initialised before any derived initialisation is done. In fact during construction the virtual function call mechanism is also initialised so calling virtual functions from a base class constructor will not call a derived override because that part of the object has not yet been initialised (a similar case exists during destruction: objects are destroyed derived to base, in the reverse order of construction).

You might have noticed that I previously used the term "directly create an object" - meaning directly via a constructor. However we can create "virtual constructor" like virtual member functions. These would work by creating new objects from existing objects. Two variations are obviously possible for all cases: a virtual create method that creates a new object using the default or other constructor (all classes in the hierarchy must have a compatible constructor) and a virtual clone method that creates new objects using the copy constructor (thereby making a clone of the object on which clone is called - all such types must be copyable of course).

Here is a simple example:

   class AbstractBase
   {
   public:
       virtual ~AbstractBase() {}
       virtual AbstractBase * Create() = 0;
       virtual AbstractBase * Clone() = 0;

   // ...

   };

   class SomeType : public AbstractBase
   {
   public:
       virtual SomeType * Create();
       virtual SomeType * Clone();

   // ...

   };

   SomeType * SomeType::Create()
   {
       return new SomeType;
   }

   SomeType * SomeType::Clone()
   {
       return new SomeType(*this);
   }


   class SomeOtherType : public AbstractBase
   {
   public:
       virtual SomeOtherType * Create();
       virtual SomeOtherType * Clone();

   // ...

   };

   SomeOtherType * SomeOtherType::Create()
   {
       return new SomeOtherType;
   }

   SomeOtherType * SomeOtherType::Clone()
   {
       return new SomeOtherType(*this);
   }

The base class AbstractBase has an empty virtual destructor and defines the two pure virtual functions Create and Clone, each of which returns a pointer to an AbstractBase.

There are two classes derived from AbstractBase: SomeType and SomeOtherType. Each of these classes implements the Create and Clone virtual functions. Note that the return types are declared to be of types SomeType * and SomeOtherType * rather than AbstractBase *. This feature is called covariant return types. It is permissible because AbstractBase * is a pointer and is an unambiguous base class of the return types specified by the functions in SomeType and SomeOtherType. Note that some older compilers (e.g. Microsoft Visual C++ 6 and earlier) do not support this feature.

The implementation of the Create and Clone functions is very formulaic: they just return a new instance of the class they are overridden in. In the case of Create the default constructor is used, in the case of Clone the copy constructor is used and *this is passed to it (this is a pointer and copy constructors take either references to (usually const) objects or an object itself (i.e. pass by value) so we have to de-reference this before passing it).

Note that you can use variations on a theme here. Maybe the classes in your class hierarchy all support some constructor that takes a specific set of parameters. In this case the Create virtual function would also take these parameters and pass them on to the class constructors. In fact you could have more than one Create method signature if required (overloading and overriding combined!).

You can find a similar answer and example in the C++ FAQ LITE at http://www.parashift.com/c++-faq-lite/, in section 20, specifically 20.8.

I would recommend you refer to this FAQ before posting questions as it may well be that your question is answered there.

---------------------- End of Previous answer text ----------------------

In fact in your case I would recommend you look at the whole of section 20 of the C++ FAQ LITE at http://www.parashift.com/c++-faq-lite/ , just to ensure you are up to speed on all the points it makes. You might then like to check out the other parts of the C++ FAQ LITE to see if it has any other useful information for you.

Hope this has been of use.

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.