I am using gcc. I am aware how the virtual destructors solve the problem when we destroy a derived class object pointed by a base class pointer. I want to know how do they work?
class A
{
public:
A(){cout<<"A constructor"<<endl;}
~A(){cout<<"A destructor"<<endl;}
};
class B:public A
{
public:
B(){cout<<"B constructor"<<endl;}
~B(){cout<<"B destructor"<<endl;}
};
int main()
{
A * a = new B();
delete a;
getch();
return 0;
}
When I change A's destructor to a virtual function, the problem is solved. What is the inner working for this. Why do I make A's destructor virtual. I want to know what happens to the vtable of A and B?
Virtual destructor is just a virtual function, so it adheres to the same rules.
When you call delete a, a destructor is implicitly called. If the destructor is not virtual, you get called a->~A(), because it's called as every other non-virtual function.
However if the destructor is virtual, you get ~B() called, as expected: the destructor function is virtual, so what gets called is the destructor of derived class, not base class.
Edit:
Note that the destructor of the base class will be called implicitly after the destructor of the derived class finishes. This is a difference to the usual virtual functions.
The key thing you need to know is that not using a virtual destructor in the above code is undefined behavior and that's not what you want. Virtual destructors are like any other virtual functions - when you call delete the program will decide what destructor to call right in runtime and that solves your problem.
Related
I understand that whenever you have a polymorphic base class, the base class should define a virtual destructor. So that when a base-class pointer to a derived-class object is deleted, it will call the destructor of the derived class first. Correct me if i am wrong here.
also, if the base-class destructor were to be non-virtual, it would be undefined behavior to delete a baseclass pointer to a derived object. Correct me if i am wrong aswell.
so my question is: Why is it exactly, that when the base-class destructor is non-virtual, the object will not be destroyed correctly?
i am assuming this is because virtual functions have some kind of table that is memorized and consulted whenever a virtual function is called. And the compiler knows that when an object is supposed to be deleted, it should call the derived destructor first.
is my assumption correct?
If at the point where you delete the object the static type of the variable is the bas type, than the destructor of the base type will be called, but the destructor of the sub class won't be called (as it is not virtual).
As a result the resources allocated by the base class will be freed, but the resources allocated by the sub class won't.
Thus the object won't be destructed correctly.
You are correct about that table: it is called a virtual method table or "vtable". But the result of the destructor being non-virtual is not that the destructors are not called in the correct order, but that the destructor(s) of the sub class(es) are not called at all!
Consider
struct Base {
void f() { printf("Base::f"); }
};
struct Derived : Base {
void f() { printf("Derived::f"); }
};
Base* p = new Derived;
p->f();
This prints Base::f, because Base::f is not virtual. Now do the same with destructors:
struct Base {
~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
~Derived() { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();
This prints Base::~Base. Now if we make the destructor virtual, then, as with any other virtual function, the final overrider in the dynamic type of the object is called. A destructor overrides a virtual destructor in a base class (even though its "name" is different):
struct Base {
virtual ~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
~Derived() override { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();
The call p->~Base() actually invokes Derived::~Derived(). Since this is a destructor, after its body finishes executing, it automatically invokes destructors of bases and members. So the output is
Derived::~Derived
Base::~Base
Now, a delete-expression is in general equivalent to a destructor call followed by a call to a memory deallocation function. In this particular case, the expression
delete p;
is equivalent to
p->~Base();
::operator delete(p);
So if the destructor is virtual, this does the right thing: it calls Derived::~Derived first, which then automatically calls Base::~Base when it's done. If the destructor isn't virtual, the likely result is that only Base::~Base is invoked.
From the C++ FAQ:
[11.4] Can I overload the destructor for my class?
No.
I realize this means you cannot change the return type, arguments' types nor the number of arguments. I may be splitting hairs on the syntax of the words, but is it possible to override the Parent's destructor?
class Child : public Parent {
public:
virtual Parent::~Parent() {
// New definition
}
};
And for that matter do it recursively?
class Grandchild : public Child {
public:
Child::Parent::~Parent() {
// An even newer definition
}
};
I've read this and a related post and it makes me think because destructors are not inherited, they cannot be overridden, but I've never seen it explicitly stated.
EDIT: I changed this to reflect the fact that I want to override the Parent's destructor, note Child and Grandchild overriding ~Parent().
The main reason I am doing this is to maintain Parent's interface while changing the way it is destroyed (the entire reason for the child class). I will have something else managing all Parent's created and will explicitly call their destructors at a later time of my choosing.
I may be splitting hairs on the syntax of the words
No, you are definitely not – these are two very different things.
but is it possible to override the destructor?
Yes, and in fact you must do this in many cases. In order for this to work for a polymorphic object, you need to declare the base class destructor as virtual, though:
Parent const& p = Child();
Will properly call p.~Child() at the end of scope because Parent::~Parent is virtual.
Yes, it is possible to override the destructor of a class. In fact, when you define a class hierarchy in which polymorphism is used, you must declare a virtual destructor in the base class.
Overrides of destructors work exactly the same way overrides of normal member functions work in that when you destroy an object by deleteing the object via a pointer to the base class, the destructor of the derived class is properly called. This is why you must have a virtual destructor in the base class for polymorphic hierarchies.
However, there is a difference between virtual destructors and virtual member methods which has nothing to do with the virtual nature of the destructor. That is, when executing code like this:
class A
{
public:
virtual void Foo() {}
virtual ~A() {};
};
class B : public A
{
public:
void Foo() {};
~B() {}
};
int main()
{
A* a = new B;
a->Foo(); // B::Foo() is called
delete a; // B is destroyed via B::~B()
}
...when you call a->Foo(), the method Foo() in B is called. Since B::Foo() doesn't explicitly call A::Foo(), A::Foo() isn't called.
However, when the object is destroyed via delete a;, first the destructor B::~B() is called, and then after that finishes but before control returns to the program, the base class destructor A::~A() is also called.
Of course this is obvious when you think about it, and again this has nothing to do with the virtual nature of the destructor, but it does behave differently than a normal virtual method call, so I thought I'd point it out.
Obligitory Standard Quotation:
[C++03] 12.4/6 : Destructors
After executing the body of the destructor and destroying any
automatic objects allocated within the body, a destructor for class X
calls the destructors for X’s direct members, the destructors for X’s
direct base classes and, if X is the type of the most derived class
(12.6.2), its destructor calls the destructors for X’s virtual base
classes. All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual
overriding destructors in more derived classes. Bases and members are
destroyed in the reverse order of the completion of their
constructor (see 12.6.2). A return statement (6.6.3) in a destructor
might not directly return to the caller; before transferring control
to the caller, the destructors for the members and bases are called.
Destructors for elements of an array are called in reverse order of
their construction (see 12.6).
Yes: you can have virtual destructors, and the only reason is to override them in derived classes.
It looks like this:
class Parent {
public:
virtual ~Parent();
};
class Child : public Parent {
public:
virtual ~Child();
};
class Grandchild : public Child {
public:
~Grandchild(); // virtual is inherited here
};
Note that the destructor isn't overridden by name like ordinary functions, because the name is always that of the class whose instance you're destroying.
Note also that the parent class' destructors are always called too, so you don't need to duplicate their cleanup code: read up on member object and base-class sub-object construction and destruction order for the details.
Terminology
overriding a function means implementing a base-class virtual function in a derived class. You can't change the signature at all (except for using covariant return types). So, an override always has the same signature as an inherited virtual function.
overloading a function means implementing multiple functions with the same name (and in some sense the same scope). So, an overload always has a different signature to the others with the same name, doesn't relate directly to virtual dispatch, and isn't necessarily inherited.
Yes; you can, and should, make a destructor virtual, whenever you have a child class which may be destroyed using a reference to the base class. Static code analysis tools will even complain if you don't offer a virtual destructor.
Consider the following example:
class A
{
public:
A() { a = new int; }
virtual ~A() { delete a; }
private:
int *a;
};
class B final : public A
{
public:
B() { b = new int; }
~B() { delete b; }
private:
int *b;
};
int main()
{
A *a = new B();
delete a;
}
If A's destructor was not virtual, then delete a would only call A's destructor, and you would end up with a memory leak. But because it's virtual, both destructors will be called, in the order ~B() -> ~A().
I know you shouldn't call any virtual function in the ctor or dtor of the base class, but what about from that of the most derived class? Should be fine right? E.g.
class base {
...
virtual void free() = 0;
};
class child : public base {
...
free() {/* free memory */}
~child() {free();}
};
Well, you can do it, but the dynamic type of *this inside child::~child() is child, and not anything more derived. So when you have a further derived class class foo : child which overrides free(), then the overridden function will not be called.
There's nothing wrong with calling a virtual function from a constructor or destructor, base class or otherwise. But you have to know what it does: the dynamic type is the class being constructed or destroyed, so it won't call an override in a class derived from the one that's being constructed or destroyed. In particular, if the function is pure virtual, you won't get an override, and the behavior is undefined. So a good rule is "don't call pure virtual functions from constructors or destructors. In your example, class::free is not pure virtual, so there's no problem calling it.
in C++: Why should the destructor of base classes be virtual?
The better question is when and why. Your question indicates that you think all base classes should have virtual destructors, which is not quite true.
It would make it impossible to apply the empty base class optimization, and could multiply the size of classes up to 16 times than what it would be without virtual on common platforms.
A virtual destructor is needed when you delete an object whose dynamic type is DerivedClass by a pointer that has type BaseClass*. The virtual makes the compiler associate information in the object making it able to execute the derived class destructor. Missing the virtual in such case causes undefined behavior.
If you don't need this, and your class is only used as a base class, it's best to make the destructor protected, thus preventing that users accidentally delete in the described way.
You want them to be virtual so that all subclass destructors are automatically called when the object is destroyed, even if it is destroyed through a pointer to the base class. In the following code:
class base {
public:
virtual ~base() { }
};
class derived : public base {
public:
~derived() { } // Inherits the virtual designation
};
int main(void)
{
base *b = new derived;
delete b;
}
The derived destructor will only be called if the base destructor is virtual.
As Magnus indicates, you don't have to do this if you aren't taking advantage of polymorphism. However, I try to develop the habit of declaring all my destructors virtual. It protects me against the case where I should have declared them virtual but forget to do so. As Johannes indicates, this habit can impose a small space and performance penalty when the virtual designation is not needed.
They dont have to be virtual unless you are using polymorphism. If you do use polymorphism they need to be virtual so that the destructors of inherited classes are guaranteed to be called, so inherited classes can do their clean up.
For situations like this:
class A
{
virtual ~A();
};
class B:A
{
~B();
};
A *a = new B(); //legal, since it's a downcast
delete a; //Unless the destructor is virtual, ~A() is called here instead of ~B().
It should be virtual to ensure that the destructor of the inherited classes are the ones actually getting called at runtime instead of the base class destructor being called.
I had a constructor in my AB.h file:
class AB{
private: int i;
public:
AB:i(0){}//constructor
~AB:i(0){} // destructor
virtual void methodA(unsigned int value)=0;};
The compiler said that:
class AB has virtual functions but non-virtual destructor
AB.h: In destructor ‘AB::~AB()’:
AC.h: error: only constructors take base initializers
if I use the ~AB(); destructor, it said that i have virtual functions but i didn't have destructor, where did I misunderstand?
Thankyou
Using an initialization list such as
AB : a_member(4),another_member(5) {}
makes only sense (and is permitted) for constructors - in a destructor, you don't want to initialize things.
In addition to this obvious syntax error, the compiler warns because AB has a virtual method but doesn't declare it's destructor virtual as well. This is recommended because of the following:
AB* ab = new SomethingDerivedFromAB();
delete ab; // calls only AB's dtor and not SomethingDeriveFromAB's unless AB declares its dtor virtual
You're getting an error and an unrelated warning.
The error is because you're using an initializer for your destructor, which doesn't make sense and isn't valid syntax.
You want:
~AB() { } // destructor
The warning is because you haven't declared your destructor virtual. Classes with virtual methods should have virtual destructors:
virtual ~AB() { }
If you have virtual functions, that's an indicator that the class is meant to be subclassed.
If you don't declare the destructor as virtual, a person with a pointer to the base class could call the destructor which won't call the sub-class's destructor because it's not a virtual destructor. Such a condition would leave the memory / items managed by the subclass in limbo as they wouldn't be properly cleaned up.
The lesson to be learned is to always make the destructor virtual, even if you already provide an implementation.
You should use virtual ~AB { } or protected: ~AB { } for your destructor.
The member initialization list : var(whatever) is for constructing objects and doesn't make sense in a destructor.
The warning about virtualness is because in general if you intend your class to be used polymorphically, you want it to be able to be deleted polymorphically as well. Alternately make the destructor protected so you can't polymorphically destroy your objects from a parent pointer.
The destructor should be virtual as you are planing to inherit from this class (methodA is virtual). However, this is just a warning.
The error is that the destructor has no argument, and obviously no initializer.
virtual ~AB() {}
class AB{
private: int i;
public:
AB:i(0){}
virtual ~AB(){}
virtual void methodA( unsigned int value ) = 0 ; };
About the virtual destructor, see the Rule of Three.
You are missing parentheses and initializing in the destructor: O.o
class AB
{
private:
int i;
public:
AB():i(0){} // <-- parentheses here
virtual ~AB() {} // <-- parentheses here
virtual void methodA(unsigned int value)=0;
};
The compiler is warning you that, while you have a virtual method in your class, your destructor is not virtual. This can lead to problems, since there may be point in your program where only the base destructor will be called.