Suppose I have:
struct Base
{
/**/ virtual /**/ ~Base() {/*..*/}
// ...
};
struct Derived : Base
{
~Derived() /* override */ {/*..*/}
// ...
};
When a class inherits from another class, overriding is here to help me to make sure I'm implementing a function that actually exists in Base.
In this scenario described above, Derived class has a different name from Base, and therefore its destructor is written differently.
My question is, in case I want to use override, where shall I use that?
Where do I really implement a Base's function in Derived class?
First of all "override" keyword simply means "this function is marked as virutal in some base class", nothing else. And it can be applied to destructors as well. Destructors however are special, normal rules don't apply to them. For example destructor in Derived, named ~Derived() is matched with destructor in Base, named ~Base(), even though formally they have different names (or do they? what is a name here anyway?).
Another difference between destructors and typical functions is that destructors are always called up the inheritance chain, regardless of implementation. And so you cannot "replace" destruction, you can only "extend" it. Note that (unlike normal functions) calling base class destructor from derived destructor is a mistake.
The chained destruction call starts at the class you are refering to at the moment. What I mean is
Base* inst = new Derived();
delete inst;
will call ~Base() because the variable inst is Base* even though it was constructed from a derived class. At this point "virtual logic" applies: if ~Base() is not virtual then normal destruction procedure fires for Base class, without being aware that the actual object is Derived*, i.e. ~Base() and all its parent desctuctors (there are none in this particular case) are executed. Which is wrong. But if it is virtual then it will actually jump to the correct class, Derived, and the correct destruction procedure is invoked: first ~Derived(), then ~Base(). See this godbolt.org and play around: add and remove "virtual" in base destructor to see the difference (look at the left column only, lines with colored background are those that are actually called).
All in all: yes, you can use ~Derived() override {}. I always use "override" where appropriate, it's nice to know which functions are derived from virtuals. Also the rule of thumb is: if Base is virtual (meaning any function is virtual) then its destructor should be virtual as well. Remember this well and it will help you avoid some problems.
As far as I know, some of C++ linter tools (like clang-tidy) already have a checking mode that could complain that your derived class doesn't mark derived virtual destructor with "override" clause. So yes, despite the fact you're not obliged to do so (according to 12.4.9 chapter of C++ Standard), you could explicitly apply "override" to catch a situation once your base class is not virtual-destructible anymore but derived classes intend to still have that.
And, yeah, just do not worry about difference is destructor names (it is a syntax catch, not more) and thing of it as void ~() method.
Related
I' ve read some articles, and as they say, main virtual destructor use cases are:
derived classes may have dynamic data allocation from heap, i.e. "own" that data object. So, they need some deletion routine in destructor. Deletion through base class pointer requires virtual declaration of destructors in all derived class till those with dynamic data allocation (base class also requires it)
this class has virtual methods. But this is unclear for me. Just calling virtual methods through base class pointer always results in the-most-derived-realization calls. They only exclusion for that rule is construction phase. Literaly, during it this object is not a derived type yet, even if later will be. Ok, what about destruction phase? As I understood, the rule is in the backward order. No matter, was destructor of some class in hierarchy declared as virtual, during each destructor this pointer is used as if of this class type, any derived were already been destroyed due to virtual d-r, or not destroyed (and that hypothetically may be ok in some design). Maybe this is the case, why d-r must be virtual? Vtable will have entries for derived class, and calling virtual methods in some base class from d-r will result in UB? Ok, but this rule applies only to case when this class calls some virtual methods in d-r, and they do have realization in derived classes.
My opinion, that there is also may be a case with no dynamic data allocation, no virtual methods in all hierarchy, but still derived destructors may do some critical tasks upon deletion (syncs, unlocks and so on). And we need virtual d-r in base class. May be such cases are results of bad design.
But anyway, developer of some public class cannot 100% know, if derived class will or not use some virtual methods in d-r, or allocate dynamic data. So, am I correct to say, that any public class, not declared as final, has to declare d-r as virtual? Only final keyword guarantees that any pointer to this class will always be of this type, and so, could be safely deleted non-virtually.
If a derived object is deleted through a pointer to the base class, then (and only then) the base class destructor must be virtual. Otherwise it is undefined behaviour. There are no other relevant rules.
If the class had a virtual function anyway, then no overhead is introduced. If the class did not have any other virtual functions, then the base class designer has to consider the trade between adding the runtime penalty of a virtual destructor, vs. the risk that a user of the class might try to delete a derived object through the base class pointer.
Here is a link to a similar discussion, with Standard quotes
In many sources, books etc. are written "don't call this->virtualFunction in child class constructor" and in some sources explain why you mustn't do it. Because at the moment of construction class isn't created at all. So virtual function that will be called from child constructor will be function of base class. It means that in child constructor body VPTR of that class pointed to base VTABLE.
So my question is,
what is the moment in object construction when VPTR of child class will be overriden to address on it's virtual table? I guess that some automatically generated code do it at end of constructor body or after constructor body will be executed.
And second question is,
why is VPTR overriden at the end of construction? Maybe for it have some important reasons?
Why can't override VPTR at beginning constructor body or after base class constructed?
Child::Child() :
Base()
//<----- Why not here?
//members initialization
{
//<----- Why not here?
//code
}
In many sources, books etc. are written "don't call this->virtualFunction in child class constructor"
I doubt that. It's often advised not to call virtual functions from the base class constructor, to avoid confusion if you expect them to call the final overrides, not the base-class versions. And you must certainly not call them from the base class if they are pure virtual there - that gives undefined behaviour.
Within the derived class constructor, they are well-defined and do what you would expect.
So virtual function that will be called from child constructor will be function of base class.
No, during the child's constructor body, the dynamic type is Child, and virtual functions calls will use the Child overrides.
what is the moment in object construction when VPTR of child class will be overriden to address on it's virtual table?
After all base class constructors have completed, and before child class members are initialised. Child member functions, including virtual functions, can be called from member initialisers (but not base class initialisers) or the constructor body.
You need to be careful calling them from member initialisers, since they might access uninitialised members. But within the constructor body, all base objects and members are initialised, so they are quite safe.
why is VPTR overriden at the end of construction?
It isn't. It happens at the first point you indicate with <----- Why not here?.
I disagree with your overly simplified reason to why you shouldn't call a virtual function. First of all, a VTABLE is not actually defined by the C++ standard, and is, in fact, implementation specific:
When is VTable in C++ created?
Calling a virtual function from a constructor is allowed by the standard, and should actually should call correctly within the hirearchy at that level (with some limitations)
C++ constructors: why is this virtual function call not safe?
http://www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from-ctors.html
However, there are many, many reasons not to do this.
The constructor for the derived class has not been called yet. Any access of any members of the derived class will yield undefined behavior.
There is a rule of thumb that you should keep constructors as simple and dumb as possible. This is due to the fact that error handling in constructors can be a giant pain due to destructor not being called and the only way to return a sensical error state is to throw an exception.
This will often break the dependency inversion principal, and may cross the line of demeter, and will usually introduce high coupling to the code.
I'm currently writing a program with the following polymorphic hierarchy: Base: Multinumber. Derived: Pairs, Complex, Rational. Multinumber is a virtual class and is never instantiated.
During the course of my program I frequently dynamically manage the base classes so I need a destructor. My question is this: how do I make the destructor virtual? In my Multinumber.h file right now I have this:
virtual ~Multinumber();
In my Multinumber.cpp:
Multinumber::~Multinumber()
{
}
And in all of my derived classes I have this:
Rational::~Rational()
{
}
I have nothing in any of my derived.h files. Unfortunately, this does not compile. Rather, I get this error:
Complex.cpp|75|error: definition of implicitly-declared 'virtual Complex::~Complex()'
What is wrong with my syntax? Thanks for any help you can give me.
Just declaring the virtual destructor in the base, and giving it the empty definition, is sufficient. For the other classes you do not need to do anything at all, unless there's actual work for those destructors to do.
The point of the virtual declaration in the base class is to ensure that the destructor can be invoked polymorphically (so that Base* d = new Derived(); delete d; works correctly, calling the Derived destructor instead of the Base destructor). You then have to define that destructor (even if it does no work) because you declared it.
However, for all of the derived classes, if you don't specify anything, the default "call destructors for members and bases" destructor gets generated for them, and everything works as you need it to. Unless, again, you need to do anything else to destruct the object properly.
As Dark Falcon noted, you need a declaration in the base for every member that you define, including destructors. So if you do write Complex::~Complex, then it must be declared in the Complex class definition, even though you inherit from a class that declares and defines a destructor. (Destructors, like constructors, aren't actually inherited anyway; the default "call recursively on members and bases" behaviour isn't really the same thing. These functions are special, since they manage the object lifetime, rather than using the object.)
Within the class Complex, you also need to have a declaration for the destructor:
~Complex();
Note that virtual is optional here. The destructor will be virtual because the base's destructor is virtual.
When to declare a destructor virtual?
I recommend you to follow this algorithm to decide whether you should declare a destructor virtual or not.
Is your class intended to be used as a base class?
No: Declare non-virtual destructor (avoids v-pointer on each object of the class) and remember not to derive from concrete classes.
Yes: Go to next question.
Is your base class abstract? (i.e. any virtual pure methods?)
No: Try to make you base class abstract by redesigning your hierarchy [1] (i.e. don't allow you base class to be instantiated).
Yes: Go to next question.
Do you want to allow polymorphic deletion though a base pointer?
No: Declare protected virtual destructor to avoid the unwanted usage.
Yes: Declare public virtual destructor (no overhead in this case).
References:
[1]: S. Meyers. More Effective C++, Item 33 (Addison-Wesley, 1996).
[2]: "Virtuality" http://www.gotw.ca/publications/mill18.htm
What is wrong with my syntax?
The following:
And in all of my derived classes I
have this:
Rational::~Rational() { }
No you don't. You didn't do it for Complex.
The question is: When to not declare the destructor virtual? There are no drawbacks to declaring a destructor virtual.
Guideline #4 link text, states:
A base class destructor should be
either public and virtual, or
protected and nonvirtual.
Probably I'm missing something, but what if I just create a concrete class, that is not designed to be used as base class.
Should I declare it's destructor public and virtual? By this I'm implicitly declate that my class is "ready to be used as base class", while this is not necessary true.
The link text specifically says"A base class destructor should be"...
The guidelines are only meant for a class which is designed to be used as a base class. If you are making a single, concrete class that will not be used as a base class, you should leave the public constructor non-virtual.
If nothing else in your class is virtual, I don't think the destructor should be virtual either.
Consider it another way around: Do you know that no one will absolutely ever try to derive from your class and when somebody does do you think he will remember to take a closer look at your dtor? Sometimes people use inheritance over composition for a good reason (provide the full interface of your class without having ugly getter syntax).
Another point for the virtual dtor is the Open/Closed Principle.
I'd go with the virtual dtor if you are not concerned with hard real-time performance or something alike.
Destructor SHALL BE virtual in any of the following cases:
Your class contains ANY virtual method.
Even if nothing is virtual you plan to use class as base.
Rare exception:
You are trying to save 4 bytes and virtual table pointer is NOT ACCEPTABLE solution because of this (example - your class HAS to fit in 32 bits because of some reason). But be prepared for hell.
Regarding public or protected - in general it is more question of how you intend to control access to destructor.
Your destructor only needs to be virtual if your class will be extended later. I'm not aware of a case where you'd want a protected/private destructor.
It's worth noting that if you have even one virtual method, you lose nothing (with most compilers) making the destructor virtual as well (but it will protect you in case somebody extends later).
The advice refers to classes with virtual functions, intended to be polymorphic base classes. You have to make sure that if someone calls delete on a base class pointer, then the destructor of the actual class is called; otherwise, resources allocated by the derived classes won't be freed.
There are two ways to achieve this:
a public virtual destructor, so the correct destructor is found at runtime; or
a protected non-virtual destructor, which prevents calling delete on a base class pointer.
For a concrete class that won't be used as a base class, you will only ever call delete on a pointer to the actual type, so the advice doesn't apply. It should have a public non-virtual destructor if it needs one.
Can the default destructor be generated as a virtual destructor automatically?
If I define a base class but no default destructor, is there a default virtual destructor
generated automatically?
No. There is a cost associated with making a method virtual, and C++ has a philosophy of not making you pay for things that you don't explicitly state that you want to use. If a virtual destructor would have been generated automatically, you would have been paying the price automatically.
Why not just define an empty virtual destructor?
In C++ 11 you can use:
class MyClass
{
// create a virtual, default destructor
virtual ~MyClass() = default;
};
Yes, by inheriting from a base class with a virtual destructor. In this case, you already pay the price for a polymorphic class (e.g. vtable).
No, all destructor's are by default NOT virtual.
You will need to define a virtual destructor on all the base classes
In addition to that.
To quote Scott Meyers in his book "Effective C++":
The C++ language standard is
unusually clear on this topic. When
you try to delete a derived class
object through a base class pointer
and the base class has a non-virtual
destructor (as EnemyTarget does), the
results are undefined
In practice, it's usually a good idea to define a class with a virtual destructor if you think that someone might eventually create a derived class from it. I tend to just make all classes have virtual destructor's anyway. Yes, there is a cost associated with that, but the cost of not making it virtual more often that not out weighs a measly bit of run-time overhead.
I suggest, only make it non-virtual when you're absolutely certain that you want it that way rather than the rely on the default non-virtual that the compilers enforce. You may disagree, however (in summary) I recently had a horrid memory leak on some legacy code where all I did was add a std::vector into one of the classes that had existed for several years. It turns out that one of it's base classes didn't have a destructor defined (default destructor is empty, non-virtual!) and as no memory was being allocated like this before no memory leaked until that point. Many days of investigation and time wasted later...
Uri and Michael are right -- I'll just add that if what's bugging you is having to touch two files to declare and define the destructor, it's perfectly all right to define a minimal one inline in the header:
class MyClass
{
// define basic destructor right here
virtual ~MyClass(){}
// but these functions can be defined in a different file
void FuncA();
int FuncB(int etc);
}
Currently, Uri is right. On the other hand, after you have declared a virtual method in your class, you are paying the price for the existence of the virtual table anyway. In fact, the compiler will warn you if your class has a virtual method, but no virtual destructor. This could become a candidate for automatic generation of the default virtual destructor instead of the pesky warning.
No. You need to declare it as virtual.
Some people stated that it is never defaulted to virtual. That's not exactly true.
Even though destructors are not inherited, if a base class declares its destructor virtual, the derived destructor always overrides it.
This means that if the base class has a virtual destructor you don't have to define a destructor of the derived class as virtual nor explicitly write:
/// All of these are unnecessary and won't change the destruction behavior
/// as long as Class inherits from a base class with a virtual destructor
virtual ~Class() = default;
// or
~Class() override = default;
// or
~Class() {}