I have two classes:
class A {
public:
virtual void somefunction() = 0;
};
class B : public A {
public:
B();
~B();
void somefunction();
};
B::B() {}
void B::somefunction() {
// some code
}
But with g++ I get errors:
class A has virtual functions and accessible non-virtual destructor
class B has virtual functions and accessible non-virtual destructor
I don't have any idea what this error is... Somewhere on blogs I read that it's a compiler warning. How can I fix the problem?
This happens because your base class A does not have a virtual destructor. For instance, if you had this code:
int main()
{
A* a = new B;
delete a;
}
Then the delete a call would not be able to call B's destructor because A's isn't virtual. (It would leak all of B's resources.) You can read more about virtual destructors here.
Add a virtual destructor to your base class and you should be fine.
class A
{
public:
virtual void somefunction() = 0;
virtual ~A() = default;
}
Give class A:
virtual ~A() { }
That way, derived classes such as B will still have their custom destructor called if you delete them via an A*.
As thumb rule(IMHO) or in Short the destructor in the base class has to be either public and virtual or protected non virtual to prevent the memory leaks.by doing so the destructors of the derived class get called and this prevents the memory leakage whenever the Base pointer/reference holding derived address/reference is deleted.
If a class has virtual functions then its destructor should be virtual as well. Yours has an accessible destructor but it is not virtual.
Related
Example:
class Base {
public:
virtual void f() = 0;
virtual ~Base() { std::cout << "Base::~Base()\n"; }
};
class Derived : public Base {
public:
void f() { }
~Derived() { std::cout << "Derived::~Derived()\n"; }
};
int main() {
Base* p = new Derived();
delete p;
return 0;
}
Output:
Derived::~Derived()
Base::~Base()
I thought only the derived class destructor will be called since the pointed object to be freed is an instance of the derived class.
I have two questions:
Why was the virtual base destructor called?
Is it legally possible (or should it even be possible) to prevent the base class destructor from being called?
Why was the virtual base destructor called?
Because base class should be properly destructed. Derived class can not possibly do this.
Is it legally possible (or should it even be possible) to prevent the
base class destructor from being called?
No, because it would prevent properly destructing the base class (i.e. call it's members destructors)
There is no explicit destructor in base class. Then, I delete the derived class with derived pointer. After that, if I access the member of the derived class, the crash happened. However, if I access the base member, the program still ok. Why?
class Base {
public:
virtual void doSomething() = 0;
protected:
virtual ~Base() {} // if I remove the destructor, then the program still run ok even if I remove the derived class.
};
class Derived: public Base {
public:
Derived() {}
~Derived() {}
void doSomething() override { a_ = true; }
private:
bool a_;
};
Derived *pD = new Derived();
Base *pB = static_cast<Base*>(pD);
delete pD;
pB->doSomething(); // the program is ok if I remove the destructor in base class
pD->doSomething(); // the program crash no matter the destructor of base class is there or not.
if I access the member of derived class, the crash happpend.
if I access the base member, the program still ok. Why?
Because the behaviour of accessing through an invalid pointer is undefined.
When I am trying to delete the derived object polymorphically (that is: base class has public virtual destructor) why derived class private destructor is still being called? Why the scope resolution private is not working here.
class Base
{
protected:
Base() { cout << "Base constructor.\n"; }
public:
virtual ~Base() { cout << "Base destructor.\n"; }
};
class Derived :public Base
{
public:
Derived() { cout << "Derived constructor.\n"; }
private:
~Derived() { cout << "Derived destructor.\n"; }
};
int main()
{
Base *p = new Derived();
delete p;
}
Output:
Base constructor.
Derived constructor.
Derived destructor.
Base destructor.
Because destructors are called in reversed order of constructors and virtual destructor will always be called.
private has nothing to do if a virtual function is going to be called.
As I pointed here out:
Why would a virtual function be private?
ISO C++ 1998 Standard onwards explicitly states:
§10.3 [...] Access control (clause 11) is not considered in determining overriding.
A bit philosophical offtopic:
Going further this is what STL does for iostreams: Definition of Non-Virtual Interface, i.e. all public functions (with exception of destructors) are non-virtual and all virtual functions are either protected or private. Public functions call virtual protected or private ones. This gives a very clear entry point into the entire hierarchy.
It is, but you're not calling ~Derived() directly. If you were to use
Derived *p = new Derived();
delete p;
then you'd get the error. But when you access ~Derived() indirectly via polymorphism (e.g. by calling ~Base()), then the access specifier private does not apply.
According to [class.access.virt#1]:
The access rules (Clause [class.access]) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it. [ Example:
class B {
public:
virtual int f();
};
class D : public B {
private:
int f();
};
void f() {
D d;
B* pb = &d;
D* pd = &d;
pb->f(); // OK: B::f() is public, D::f() is invoked
pd->f(); // error: D::f() is private
}
— end example ]
And again in footnote 111 in [class.virtual]:
Access control is not considered in determining overriding.
You use a virtual destructor because you want all the destructor in your inheritance to get called. That exactly what you get. The private does not apply as you don't call the destructor explicitly.
If your destructor was not virtual you will get only Base::~Base() called. Usually that's not what you want when you have polymorphism.
You can call the destructor through a pointer to B, because it's already public there. It's the static type of the pointer which is used to determine that access in this case.
[class.access.virt/1]
The access rules (Clause [class.access]) for a virtual function are
determined by its declaration and are not affected by the rules for a
function that later overrides it. [ Example:
class B {
public:
virtual int f();
};
class D : public B {
private:
int f();
};
void f() {
D d;
B* pb = &d;
D* pd = &d;
pb->f(); // OK: B::f() is public, D::f() is invoked
pd->f(); // error: D::f() is private
}
— end example ]
This keeps virtual functions in line with the Liskov Substitution Principle
You delete the derived class through the base class pointer. With the help of the virtual destructor you start the delete at the derived class. Because that class can access its private members, it call the private destructor. After that the base class is calling the public destructor.
Note that you call delete and not calling de destructor Derived::~Derived() direct!
Example code:
#include <string>
namespace vehicle
{
class Vehicle
{
public:
Vehicle(int a);
virtual ~Vehicle(); <------ not method?
protected:
int a;
};
}
Also, I don't fully get the concept of a pure virtual method where you declare a method as:
virtual method() = 0;
Why do we need this?
Let's suppose there are two classes: Base and Derived
struct Base
{
Base() {}
virtual void foo() = 0;
virtual ~Base()
{
std::cout << "Base descructor" << std::endl;
}
};
struct Derived : Base
{
int *i;
Derived(int i_): Base(), i(new int[i_]) {}
virtual void foo() override
{
std::cout << "foo" << std::endl;
}
virtual ~Derived()
{
std::cout << "Derived descructor" << std::endl;
delete [] i;
}
};
Pure virtual functions
If Derived doesn't override the foo function you can create an instance of the Derived class. When you try, your code will not compile, because foo is a pure virtual function.
error: invalid new-expression of abstract class type 'Derived'
note: because the following virtual functions are pure within 'Derived':
struct Derived : Base
Pure virtual functions are used to describe the interface.
Now about virtual destructors:
The ~(tilda) sign is used to denote the class destructor. It
is a special method that is called when the object is destroyed.
A client creates an instance of Derived:
Base *instance = new Derived;
then this variable is used somehow and when you don't need the variable you need to free the memory:
delete instance;
Let's trace the calls:
Derived descructor
Base descructor
So you can see that both base and derived destructors are called and no memory leak is possible. But if you remove this virtual keyword from the destructors
Base descructor
As you can see the descturtor of Derived is not called, so a memory leak exists (the array of Derived class don't get released).
Hence virtual constructors are useful when you work with objects through pointers.
virtual ~Vehicle();
The tilde ~ denotes a destructor. It's a method, a special method for destroy the object.
Virtual destructor is used in abstract base class.
virtual method() = 0;
That's pure virtual function. It indicates that you have to provide implementation method for the implementation class implementing this abstract base class.
Why are all destructors, ~D(),~C(),~B(),~A() being called in the example below?
There is only one virtual destructor: that of A.
Here is the code:
#include<iostream>
using namespace std;
class A
{
public:
virtual ~A()
{
cout<<"destruct A\n";
}
};
class B:public A
{
public:
~B()
{
cout<<"destruct B\n";
}
};
class C:public B
{
public:
~C()
{
cout<<"destruct C\n";
}
};
class D:public C
{
public:
~D()
{
cout<<"destruct D\n";
}
};
int main()
{
A* ptr = new D();
delete ptr;
return 0;
}
Once A's destructor is declared virtual, the destructors of all derived classes are also virtual, even if they aren't explicitly declared as such.. So the behaviour you see is exactly what is expected
The destruction order in derived objects goes in exactly the reverse
order of construction: first the destructors of the most derived
classes are called and then the destructor of the base classes.
A destructor can be defined as virtual or even pure virtual. You would
use a virtual destructor if you ever expect a derived class to be
destroyed through a pointer to the base class. This will ensure that
the destructor of the most derived classes will get called:
A* b1 = new B;//if A has a virtual destructor
delete b1;//invokes B's destructor and then A's
A* b1 = new B;//if A has no virtual destructor
delete b1;//invokes A's destructor ONLY
If A does not have a virtual destructor, deleting b1 through a pointer
of type A will merely invoke A's destructor. To enforce the calling of
B's destructor in this case we must have specified A's destructor as
virtual:
virtual ~A();
REFERENCE
As #juanchopanza said - declaring the base destructor virtual means all descendants have virtual destructors. This inherited virtuality is the same for any methods, not just destructors.
It's why I have interviewed people who didn't know what the keyword did because they had only ever had to override methods derived from a framework, so they were all virtual (sigh).