0

I figured out 2 different situations where virtual is used.

  • If a baseClass has a function defined virtual, then the derivedClass is going to override the function.

  • The baseClass::~baseClass() should be defined virtual, if there is any class derived from it. Here it means, the derived class destruction first takes place followed by base class destruction.

Are there any other situations where virtual is used ?

Mahesh
  • 34,573
  • 20
  • 89
  • 115
  • 2
    There are no "two different meanings" in what you described. The mechanism that works in both cases is exactly the same, be that destructor or any other virtual function. You have only one meaning so far. What are you trying to do? BTW, derived destruction always takes place before base destruction. This has absolutely nothing to do with `virtual`. – AnT stands with Russia Jan 07 '11 at 06:04
  • @AndreyT - `In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.` Taken from docs. – Mahesh Jan 07 '11 at 06:09
  • @Mahesh: That means you only need a virtual destructor if you delete objects polymorphically. That's often the case, but by no means universally done. – Ben Voigt Jan 07 '11 at 06:12
  • @Mahesh: What he means is that your text, while true, isn't what you meant and is *always* true. Given: `struct b {}; struct d : b {}; d x;`, `x` will have the derived destructor called first. This is the case for all derived classes. Rather, `virtual` here (like your first point, as Andrey says), just ensures the destructor is called polymorphically. That is, given `b* x = new d; delete x;`, the derived class's destructor will be called. So your second "point" is just a special case of the first. – GManNickG Jan 07 '11 at 06:14
  • @Mahesh: Great. Now, what does this have to do with what you said before? All your quote says is that in order to invoke the destructor in accordance with the *dynamic* type of the object, the destructor shall be virtual. This is exactly how it is with any other virtual function. – AnT stands with Russia Jan 07 '11 at 06:27
  • @Everyone - I should have said the point `Destructor should be virtual when class is polymorphic`. Thanks for all the inputs :) – Mahesh Jan 07 '11 at 06:51
  • 1
    @Mahesh: While it is a good practice to declare virtual destructor in polymorphic class, it is still not required from the formal point of view. Virtual destructor is only required for *polymorphic deletion* of the class. However, just because some class is polymorphic, it still does not mean that you will delete it polymorphically, and thus still does not mean that it needs virtual destructor. – AnT stands with Russia Jan 07 '11 at 06:56

7 Answers7

1

virtual always has the same meaning when applied to a member function. When a member function is virtual, it means that calls to that member function will be dispatched dynamically.

That is, the function to be called will be selected based on the dynamic type (the actual type), not the static type. Based on the actual type of the object, the final overrider of the virtual function will be called.

The only reason that destructors are "different" is that a derived class destructor has a different name than the base class destructor. The behavior of the derived class destructor is not affected by it being declared virtual, though: a derived class destructor always calls base class destructors after it has run.


As an example of the behavior of virtual functions:

struct B {
    void f() { }
    virtual void g() { }
};

struct D : B {
    void f() { }
    virtual void g() { }
};

int main() {
    B* p = new D();
}

The dynamic type of the expression *p is D because the actual type of the object pointed to by p is a D. You used new D() to create it, so it's dynamic type is D.

The static type of the expression *p is B because that is the type named in the code. Without running the program or evaluating what got assigned to p, the compiler doesn't know the most derived type of the object given by *p; it just knows that whatever it is, it is a B or something derived from B.

If you call p->f(), the call is dispatched statically because B::f is not virtual. The compiler looks at the static type of *p and selects the function to be called based on that (B::f).

If you call p->g(), the call is dispatched dynamically because B::g is virtual. At runtime, the dynamic type of the object is checked (using a vtable in many common implementations), and the final overrider is called. In this case, the final overrider is D::g because D is the most derived class that overrides B::g (if there was another class derived from D, it could opt to override B::g as well).

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • @Mahesh: No. The static type and the dynamic type can only differ when you have references or pointers. The static type is always what it says in the code. If you say `BaseClass* p = new DerivedClass()`, the static type of `*p` is `BaseClass` because that's what it says in the code. However, the dynamic type of `*p` is `DerivedClass` because that is the actual type of the object. – James McNellis Jan 07 '11 at 05:59
  • If you just have an object not accessed through a pointer or reference, the static type and the dynamic type must be the same: given `BaseClass x;`, `x` is always of type `BaseClass`, period. – James McNellis Jan 07 '11 at 06:00
  • @Mahesh: I've tried to add a more detailed explanation. (Though, as this answer gets longer, the chance of it containing inaccurate or incorrect information grows; if anyone has any corrections or suggestions, please leave a comment and let me know. I'm sure someone else can provide a clearer explanation as well; if so, I'd be happy to upvote it.) – James McNellis Jan 07 '11 at 06:14
1

There's also virtual inheritance, where the base class is referenced by an indirection.

In C++, what is a virtual base class?

Community
  • 1
  • 1
Fred Larson
  • 60,987
  • 18
  • 112
  • 174
0

Virtual Base Class.

Also read C++-FAQ :What is the "dreaded diamond"?

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
0

virtual inheritance is a big one. among other things it resolves issues with duplicate members introduced by multiple inheritance. google "dreaded diamond pattern" for the full details there.

Nick
  • 8,181
  • 4
  • 38
  • 63
0

Example of virtual inheritance,

class UltimateBase{};
class Base1 : public virtual UltimateBase{};
class Base2 : public virtual UltimateBase {};

class Derived : public Base1, public Base2{};

So that instances of Derived class may have only one subobject of UltimateBase class.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
0

there is actually one more little quirk with virtual. let's say you have a class which you would like to be what for example java, c#, php and actionscript would call abstract, but this class has no pure virtual methods. then you can declare the destructor as a pure virtual method in the class declaration, but still implement it. here's an example:

#include <iostream>

class MyAbstractClass
{
    public:
        MyAbstractClass(int i);
        virtual ~MyAbstractClass() = 0;
        int getI() const;
    private:
        int m_i;
};

class MyConcreteClass : public MyAbstractClass
{
    public:
        MyConcreteClass(int i);
        ~MyConcreteClass();
};

MyAbstractClass::MyAbstractClass(int i) :
    m_i(i)
{
    std::cout << "constructor of MyAbstractClass\n";
}

MyAbstractClass::~MyAbstractClass()
{
    std::cout << "destructor of MyAbstractClass\n";
}

int MyAbstractClass::getI() const
{
    return m_i;
}

MyConcreteClass::MyConcreteClass(int i) :
    MyAbstractClass(i)
{
    std::cout << "constructor of MyConcreteClass\n";
}

MyConcreteClass::~MyConcreteClass()
{
    std::cout << "destructor of MyConcreteClass\n";
}

int main(int argc, char* argv[])
{
    MyConcreteClass a(5);
    std::cout << a.getI();
    std::cout << std::endl;
    MyAbstractClass b(5); //compile error, can't instantiate a class with abstract functions

    return 0;
}
davogotland
  • 2,718
  • 1
  • 15
  • 19
0

The virtual keyword gives the function late binding. In late binding the function call is not bound to anything until run time. In polymorphism and at run time the class looks up its v-table to decide what overloaded function to call. The destructor is often virtual when its class is polymorphic. virtual is probably the most opposite to inline, and very similar (at least in my opinion) to extern.

motoku
  • 1,571
  • 1
  • 21
  • 49