Consider the following code snippet:
class A
{
virtual void function();
public:
virtual ~A() {};
}
class B: public A
{
virtual void function() override final;
public:
/*virtual*/ ~B() {}; // does this d-tor have to be declared at all?
}
I can find the info regarding the base class destructor easily, e.g. http://en.cppreference.com/w/cpp/language/destructor
"Deleting an object through pointer to base invokes undefined behavior
unless the destructor in the base class is virtual. A common
guideline is that a destructor for a base class must be either public
and virtual or protected and nonvirtual"
A virtual destructor in a base class is a must, how about the derived class's destructors, do they have to be explicitly declared/defined? I find it quite confusing, since the destructors of the derived classes are automatically virtual too. Is it legal in terms of vtable addressing to skip the derived class's destructor's declaration/definition? What about the following situation:
class A
{
virtual void function();
public:
virtual ~A() {};
}
class B: public A
{
virtual void function() override;
public:
/*virtual*/ ~B() {}; // does this d-tor have to be declared at all?
}
class C: public B
{
virtual void function() override final;
public:
/*virtual*/ ~C() {}; // does this d-tor have to be declared at all?
}
There is no need to define explicitly destructors in derived classes. According to the C++ Standard
If a class has a base class with a virtual destructor, its destructor
(whether user- or implicitly-declared) is virtual
Also if you bother about the access control then
An implicitly declared destructor is an inline public member of its
class.
The compiler will place the address of its implicitly defined destructor in vtable. So vtable for derived classes will store addresses of destructors of derived classes.
For readability of your code you could write for example
class B: public A
{
virtual void function() override final;
public:
virtual ~B() = default;
}
No, it does not need to be declared; classes that inherit from classes with a given function declared to be virtual do not need to declare their inherited form to be virtual for it to be virtual. This includes destructors which are implicitly declared.
As others have stated, no, you don't need to declare a do-nothing destructor in descendent classes because it carries down from the ancestor class.
However, keep in mind that your class C might be derived from some third-party library class B in something like VendorBAwesomeness.dll, and B might in turn be derived from Microsoft's class A in mswonderful.dll.
If you want to be nice to the readers and users of your class, you should consider specifying virtual in your class C because you saw it in the interface for class B when you read about it, and the author of class B did the same when he/she learned about class A.
By passing this information down, you're allowing others to see clearly what your code does without them having to hunt around for the information.
Related
I was recently reading about virtual functions and virtual destructors, and the following question aroused.
For instance, I have the following inheritance chain.
class Base
{
public:
virtual ~Base() // note: virtual
{
std::cout << "Calling ~Base()\n";
}
};
class Derived: public Base
{
public:
~Derived()
{
std::cout << "Calling ~Derived()\n";
}
};
I read that virtual functions of the base class are implicitly virtual by-default in the derived classes. So, I thought that the same would apply to the destructors.
I would like to know, if the destructor of the derived class is virtual by-default. If not, I would be delighted if you provided some explanation.
I thought that the same would apply to the destructors
It does, yes.
I would like to know, if the destructor of the derived class is virtual by-default
In this example, yes it is.
Once something has been marked virtual, all overriding descendants of that something are also virtual, whether they state it explicitly or not.
So, if a method is virtual, all derived methods that override it are also virtual. If a destructor is virtual, all derived destructors are also virtual.
I know that virtual propagates to the derived class method and it's optional to put as keyword on the method declaration on the derived class, and i know that i MUST mark as virtual the destructor of the base class, in order to have polymorphic destruction, but what i want to know is if the default destructor of the derived class, inherit the virtual from the virtual destructor of the base class, and so i have to explicit write it on the derived class.
Example:
class A{
public:
virtual ~A() override = default;
}
class B: public A{
public:
// have i to write this or it's already what the compiler get as default?
virtual ~B() override = default;
}
The destructor for a derived class, despite having a different name from the destructor of the base class, overrides the base class destructor. Just like any other override, it’s virtual if the one it overrides is virtual.
Yes once a member function (destructor included) is marked as virtual in the base class, it remains virtual in all derived classes.
You can omit the keyword virtual in ~B() declaration, and even omit ~B() entirely, if it's empty.
I'm confused about overriding functions when the derived class isn't immediately derived, but derived from an already derived class.
#include <iostream>
struct Base
{
virtual ~Base() { std::cout << "Base destructor called\n"; }
};
struct Derived : Base
{
Derived() {}
// Implicitly supplied destructor, I'm guessing. Which is also virtual?
};
struct MostDerived : Derived
{
MostDerived(){};
~MostDerived() { std::cout << "MostDerived destructor called\n"; }
};
int main()
{
Derived* d = new MostDerived();
delete d;
Base* b = new MostDerived();
delete b;
}
In both cases MostDerived's destructor is called. I'm wondering if it's only required that the most base class has a destructor declared virtual, and in that case all other classes inheriting from it all have virtual destructors that override every other destructor further upstream, if you get my meaning.
I'm not sure if I made sense, basically if I had a series of 10 classes with each one inheriting from the last one, any destructor in the chain will override all the destructors that are more base than it?
struct GreatGrandfather{~virtual GreatGrandfather(){}}; // Only this is necessary
struct Grandfather : GreatGrandfather {};
struct Father : Grandfather{};
struct Son : Father{};
struct Grandson : Son {};
struct GreatGrandson : Grandson{};
Grandson's destructor will override all of the classes above it, but not GreatGrandson's destructor?
And also, once a base class's destructor or other function is declared virtual none of its descendants need to be declared virtual again?
any destructor in the chain will override all the destructors that are more base than it?
Yes, pretty much. A destructor will be implicitly supplied by the implementation if you don't write one. So it will also implicitly override the base class d'tor.
Grandson's destructor will override all of the classes above it, but not GreatGrandson's destructor?
It will override Son's d'tor. Which by extension overrides Father's and so forth. So yes. And it can't override GreatGrandson, since at the point of its definition it cannot look into the future and know GreatGrandson will exist.
And also, once a base class's destructor or other function is declared virtual none of its descendants need to be declared virtual again?
Yes, same as with any virtual function. Once declared virtual, it's always virtual in any derived class.
A destructor overrides all virtual destructors of base classes, including indirect bases. Also, a function that overrides a virtual function is itself virtual. Therefore, yes, the implicitly defined destructor of Derived is virtual, and both ~Base and ~Derived are overridden by ~MostDerived. When a pointer to a base class is used to destroy an object of derived class type, the destructor that needs to be virtual is that of the base class. (The one in the derived class will then be implicitly virtual.)
class Base
{
virtual void bePolymorphic() = 0; // Will never be used
};
class Derived : Base
{
virtual void bePolymorphic() override {}; // I have to do this in every derived class
};
This is the hack that I have been using recently to make Base an abstract class if it doesn't have any member functions.
In Java there is an abstract keyword. Why isn't there one in C++? Is there another way of making a class abstract?
The classic work-around to this problem* is to make destructor pure virtual. Of course you must implement it outside the class:
// In the header file
class Base {
virtual ~Base() = 0;
};
// In the source file
Base::~Base() {
}
* This suggestion comes from one of Scott Meyers' books.
No. There is no abstract specifier in C++. The equivalent is to make your constructor protected:
class Base
{
protected:
Base() {}
virtual ~Base() {}
}
In addition, the C++ equivalent of a Java interface is one in which all of your methods are pure virtual, as you have, and the constructor is protected.
Also note that it's a good idea to always make the destructor virtual in a base class. If a derived class needs a destructor and the parent's destructor isn't virtual, the derived's constructor won't be called.
I find The rule of Zero as also mentioned on Peter Sommerlads Slides (p.32) very compelling.
Although, I seem to remember that there was a strict rule that one has to define the destructor virtual, if the class has virtual members and is actually derived.
struct Base {
virtual void drawYourself();
virtual ~Base() {}
};
struct Derived : public Base {
virtual void drawYourself();
};
The body of the destructor may even be empty (it only needs the entry in the vtbl).
I seem to remember that when use the hierarchy
int main() {
Base *obj = new Derived{};
obj->drawYourself(); // virtual call to Derived::drawYourself()
delete obj; // Derived::~Derived() _must_ be called
}
then it is important that delete obj calls the correct destructor. Is it correct, that if I left out the destructor definition totally, it would not become virtual, and therefore the wrong d'tor would be called?
struct Base {
virtual void drawYourself();
// no virtual destructor!
};
This leads me to my final question:
Is the "Rule Of Zero" also true in hierarchies with virtual methods
or do I need to define the virtual destructor in these cases?
Edit: As I was reminded in an answer, my 1sr version of the question had the wrong assumptions. The relevant (virtual) destructor is in Base, not Derived. But my question holds: Do I need to declare (virtual) destructors at all?
It's actually the base destructor that has to be declared virtual, and it's automatically virtual in derived classes:
struct Base {
virtual void drawYourself();
virtual ~Base() = default;
};
struct Derived : public Base {
virtual void drawYourself();
};
But other than that, the rule of zero still holds.
If you do it the way you did it, or if you leave out the virtual destructor, you simply get undefined behavior when deleteing a derived object through a base pointer.