6

I was trying to familiarize myself with the OOP concepts but could not quite understand the concept of virtual.

  1. One can create a virtual destructor but not a virtual constructor. Why?
  2. How are virtual destructors handled internally? I mean the link Virtual Destructors illustrates the concept but my question is how the vptr of both the vtables (Derived and Base) are called? (In case of virtual member functions when such a scenario occurs generally the function that vptr of Derived class points to is only called)
  3. Are there any other scenarios where one may need to use a virtual destructor?

Can anyone please help me understand the above concepts with links/examples?

Niall
  • 30,036
  • 10
  • 99
  • 142
SohamC
  • 2,367
  • 6
  • 22
  • 34
  • 3
    1. [Why do we not have a virtual constructor in C++?](http://stackoverflow.com/questions/733360/why-do-we-not-have-a-virtual-constructor-in-c) 2. [Mechanism of Vptr and Vtable in C++](http://stackoverflow.com/questions/19224126/mechanism-of-vptr-and-vtable-in-c) 3. [When to use virtual destructors?](http://stackoverflow.com/questions/461203/when-to-use-virtual-destructors) – Sufian Latif Sep 11 '14 at 06:16

6 Answers6

9

First, a little about the difference between virtual functions and non-virtual functions:

Every non-virtual function-call that you have in your code can be resolved during compilation or linkage.

By resolved, we mean that the address of the function can be computed by the compiler or the linker.

So in the object code created, the function-call can be replaced with an op-code for jumping to the address of that function in memory.

With virtual functions, you have the ability to invoke functions which can be resolved only during runtime.

Instead of explaining it, let's run through a simple scenario:

class Animal
{
    virtual void Eat(int amount) = 0;
};

class Lion : public Animal
{
    virtual void Eat(int amount) { ... }
};

class Tiger : public Animal
{
    virtual void Eat(int amount) { ... }
};

class Tigon : public Animal
{
    virtual void Eat(int amount) { ... }
};

class Liger : public Animal
{
    virtual void Eat(int amount) { ... }
};

void Safari(Animal* animals[], int numOfAnimals, int amount)
{
    for (int i=0; i<numOfAnimals; i++)
        animals[i]->Eat(amount);
    // A different function may execute at each iteration
}

As you can probably understand, the Safari function allows you to be flexible and feed different animals.

But since the exact type of each animal is not known until runtime, so is the exact Eat function to be called.


The constructor of a class cannot be virtual because:

Calling a virtual function of an object is performed through the V-Table of the object's class.

Every object holds a pointer to the V-Table of its class, but this pointer is initialized only at runtime, when the object is created.

In other words, this pointer is initialized only when the constructor is called, and therefore the constructor itself cannot be virtual.

Besides that, there is no sense for the constructor to be virtual in the first place.

The idea behind virtual functions is that you can call them without knowing the exact type of the object with which they are called.

When you create an object (i.e., when you implicitly call a constructor), you know exactly what type of object you are creating, so you have no need for this mechanism.


The destructor of a base-class has to be virtual because:

When you statically allocate an object whose class inherits from the base-class, then at the end of the function (if the object is local) or the program (if the object is global), the destructor of the class is automatically invoked, and in turn, invokes the destructor of the base-class.

In this case, there is no meaning to the fact that the destructor is virtual.

On the other hand, when you dynamically allocate (new) an object whose class inherits from the base-class, then you need to dynamically deallocate (delete) it at some later point in the execution of the program.

The delete operator takes a pointer to the object, where the pointer's type may be the base-class itself.

In such case, if the destructor is virtual, then the delete operator invokes the destructor of the class, which in turn invokes the destructor of the base-class.

But if the destructor is not virtual, then the delete operator invokes the destructor of the base-class, and the destructor of the actual class is never invoked.

Consider the following example:

class A
{
    A() {...}
    ~A() {...}
};

class B: public A
{
    B() {...}
    ~B() {...}
};

void func()
{
    A* b = new B(); // must invoke the destructor of class 'B' at some later point
    ...
    delete b; // the destructor of class 'B' is never invoked
}
barak manos
  • 29,648
  • 10
  • 62
  • 114
3

One can create a virtual destructor but not a virtual constructor. Why?

Virtual functions are dispatched according to the type of the object they're called on. When a constructor is called, there is no object - it's the constructor's job to create one. Without an object, there's no possibility of virtual dispatch, so the constructor can't be virtual.

How are virtual destructors handled internally?

The internal details of virtual dispatch are implementation-defined; the language doesn't specify the implementation, only the behaviour. Typically, the destructor is called via a vtable just like any virtual function.

how the vptr of both the vtables (Derived and Base) are called?

Only the most-derived destructor will be called virtually. All destructors, virtual or not, will implicitly call the destructors of all member and direct base-class subobjects. (The situation is slightly more complicated in the presence of virtual inheritance; but that's beyond the scope of this question).

Are there any other scenarios where one may need to use a virtual destructor?

You need one in order to support polymorphic deletion; that is, to be able to delete an object of derived type via a pointer to a base type. Without a virtual destructor for the base type, that's not allowed, and will give undefined behaviour.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • _"Typically, the destructor is called via a vtable just like any virtual function."_ - This seems to imply that virtual function calls in general aren't implementation defined, which they are IIRC. I'm sure that's what you meant but the sentence is somewhat ambiguous. – rjnilsson Sep 11 '14 at 06:40
  • @Cwan: It might imply that, if I hadn't just said "The language doesn't specify the implementation, only the behaviour", and qualified with the word "typically". But I've added yet more qualification, in case anyone else finds it ambiguous. – Mike Seymour Sep 11 '14 at 06:47
  • Yeah, well, as English isn't my native language I might very well have been mistaken. Much clearer now though IMHO. – rjnilsson Sep 11 '14 at 11:07
2
  1. because a Virtual function is invoked at runtime phase, however constructors are invoked at initialization phase, object is not constructed. So it's meaningless to have a virtual constructor.

  2. a. the reason why only the base class desctructor is invoked in your link, the destructor is not marked as virtual, so the desctructor address is linked to Base class destructor at compile/link time, and obviously the type of the pointer is Base instead of Derived at compile time.

    b. for why both of Base and Derived constructors are invoked after adding virtual to Base desctructor. It's same behavior like below: Derived d; // when d exits the lifecycle, both Derived and Base's desctructor will be invoked.

  3. Suppose when you have at least one virtual function, you should have a virtual desctructor.

cck3rry
  • 191
  • 2
2

One can create a virtual destructor but not a virtual constructor. Why?

I'll try and explain this in layman's terms. A class in c++ only exists after it's constructor completes. Each base class exists prior to initialisation of derived class and its members (vtable links included). Hence, having a virtual constructor does not make sense (since to construct, you need to know the type). Furthermore (in c++), calling virtual functions from a constructor does not work (as the derived class's vtable part has not been set up). If one thinks about it carefully, allowing virtual functions to be called from a contructor opens up a can of worms (such as what if virtual functions of derived classes are called prior to member initialization).

As far as destructors are concerned, at the point of destruction, the vtable is "intact", and we (c++ runtime) are fully aware of the type (so to speak). The destructor of the most derived part of the type is found (if virtual, through vtable), and therefore that destructor, and naturally that of all bases can be called.

How are virtual destructors handled internally? I mean the link Virtual Destructors illustrates the concept but my question is how the vptr of both the vtables (Derived and Base) are called?

Destructors are handled the same as normal virtual functions (that is, there addresses are looked up in a vtable if they are virtual at the expense of one (perhaps 2?) extra level/s of indirection). Furthermore, c++ guarantees that all base destructors shall execute (in opposite order of construction which relies on order of declaration) after completion of a derived destructor.

One can mimick/simulate virtual construction by using patterns such as the prototype pattern (or cloning), or by using factories. In such cases either an instance of the real type exists (to be used polymorphically), or a factory exists (deriving from abstract factory), that creates a type (via virtual function) based on some knowledge provided.

Hope this helps.

Werner Erasmus
  • 3,988
  • 17
  • 31
0

I assume we have a Base class A, and it's derived B.

1.: You can delete B via an A pointer, and then the correct method is to call the B destructor too. However, you just can't say, that a B object should be created while you actually just call the A constructor. There is just not such a case. You can say:

A* a = new B ();

or

B b;

But both directly call the B's constructor.

2.: Well, i am not entirely sure, but i guess it will iterate through the relevant part of the class hierarchy, and search for the closest call of the function. If a function is not virtual, it stop iterating and call it.

3.: You should always use virtual destructor, if you want to inherit something from that class. If it's a final class, you shouldn't.

Melkon
  • 418
  • 3
  • 12
0

I wasted a couple of days trying to discover why my derived virtual destructors were not being called before discovering the answer so hopefully I can save other a lot of grief with this reply.

I started using derived classes three and four levels deep in my project. Virtual functions seemed to work fine but then I discovered I had massive memory leaks because my destructors were not being called. No compiler or runtime error - the destructors just were not being called.

There is a ton of documentation and examples about this on the web but none of it was useful because my syntax was correct.

I decided that if the compiler wasn't going to call my destructors, I needed to create my own virtual destruct method to call. Then I got the compiler error that solved the problem - "class if a Forward Reference". Adding an include for the derived class header files in the base class solved the problem. The compiler needs the class definition to call the destructor!

I suggest when creating a new derived class, include the header file in the base and intermediate classes. Probably also a good idea to add conditional debug code to your destructors to check that they are bing called.

Bob Rice

Bob Rice
  • 11
  • 1