Related
I was trying to familiarize myself with the OOP concepts but could not quite understand the concept of virtual.
One can create a virtual destructor but not a virtual constructor. Why?
How are virtual destructors handled internally? I mean the link Virtual Destructors illustrates the concept but my question is how the vptr of both the vtables (Derived and Base) are called? (In case of virtual member functions when such a scenario occurs generally the function that vptr of Derived class points to is only called)
Are there any other scenarios where one may need to use a virtual destructor?
Can anyone please help me understand the above concepts with links/examples?
First, a little about the difference between virtual functions and non-virtual functions:
Every non-virtual function-call that you have in your code can be resolved during compilation or linkage.
By resolved, we mean that the address of the function can be computed by the compiler or the linker.
So in the object code created, the function-call can be replaced with an op-code for jumping to the address of that function in memory.
With virtual functions, you have the ability to invoke functions which can be resolved only during runtime.
Instead of explaining it, let's run through a simple scenario:
class Animal
{
virtual void Eat(int amount) = 0;
};
class Lion : public Animal
{
virtual void Eat(int amount) { ... }
};
class Tiger : public Animal
{
virtual void Eat(int amount) { ... }
};
class Tigon : public Animal
{
virtual void Eat(int amount) { ... }
};
class Liger : public Animal
{
virtual void Eat(int amount) { ... }
};
void Safari(Animal* animals[], int numOfAnimals, int amount)
{
for (int i=0; i<numOfAnimals; i++)
animals[i]->Eat(amount);
// A different function may execute at each iteration
}
As you can probably understand, the Safari function allows you to be flexible and feed different animals.
But since the exact type of each animal is not known until runtime, so is the exact Eat function to be called.
The constructor of a class cannot be virtual because:
Calling a virtual function of an object is performed through the V-Table of the object's class.
Every object holds a pointer to the V-Table of its class, but this pointer is initialized only at runtime, when the object is created.
In other words, this pointer is initialized only when the constructor is called, and therefore the constructor itself cannot be virtual.
Besides that, there is no sense for the constructor to be virtual in the first place.
The idea behind virtual functions is that you can call them without knowing the exact type of the object with which they are called.
When you create an object (i.e., when you implicitly call a constructor), you know exactly what type of object you are creating, so you have no need for this mechanism.
The destructor of a base-class has to be virtual because:
When you statically allocate an object whose class inherits from the base-class, then at the end of the function (if the object is local) or the program (if the object is global), the destructor of the class is automatically invoked, and in turn, invokes the destructor of the base-class.
In this case, there is no meaning to the fact that the destructor is virtual.
On the other hand, when you dynamically allocate (new) an object whose class inherits from the base-class, then you need to dynamically deallocate (delete) it at some later point in the execution of the program.
The delete operator takes a pointer to the object, where the pointer's type may be the base-class itself.
In such case, if the destructor is virtual, then the delete operator invokes the destructor of the class, which in turn invokes the destructor of the base-class.
But if the destructor is not virtual, then the delete operator invokes the destructor of the base-class, and the destructor of the actual class is never invoked.
Consider the following example:
class A
{
A() {...}
~A() {...}
};
class B: public A
{
B() {...}
~B() {...}
};
void func()
{
A* b = new B(); // must invoke the destructor of class 'B' at some later point
...
delete b; // the destructor of class 'B' is never invoked
}
One can create a virtual destructor but not a virtual constructor. Why?
Virtual functions are dispatched according to the type of the object they're called on. When a constructor is called, there is no object - it's the constructor's job to create one. Without an object, there's no possibility of virtual dispatch, so the constructor can't be virtual.
How are virtual destructors handled internally?
The internal details of virtual dispatch are implementation-defined; the language doesn't specify the implementation, only the behaviour. Typically, the destructor is called via a vtable just like any virtual function.
how the vptr of both the vtables (Derived and Base) are called?
Only the most-derived destructor will be called virtually. All destructors, virtual or not, will implicitly call the destructors of all member and direct base-class subobjects. (The situation is slightly more complicated in the presence of virtual inheritance; but that's beyond the scope of this question).
Are there any other scenarios where one may need to use a virtual destructor?
You need one in order to support polymorphic deletion; that is, to be able to delete an object of derived type via a pointer to a base type. Without a virtual destructor for the base type, that's not allowed, and will give undefined behaviour.
because a Virtual function is invoked at runtime phase, however constructors are invoked at initialization phase, object is not constructed. So it's meaningless to have a virtual constructor.
a. the reason why only the base class desctructor is invoked in your link, the destructor is not marked as virtual, so the desctructor address is linked to Base class destructor at compile/link time, and obviously the type of the pointer is Base instead of Derived at compile time.
b. for why both of Base and Derived constructors are invoked after adding virtual to Base desctructor. It's same behavior like below:
Derived d; // when d exits the lifecycle, both Derived and Base's desctructor will be invoked.
Suppose when you have at least one virtual function, you should have a virtual desctructor.
One can create a virtual destructor but not a virtual constructor.
Why?
I'll try and explain this in layman's terms.
A class in c++ only exists after it's constructor completes. Each base class exists prior to initialisation of derived class and its members (vtable links included). Hence, having a virtual constructor does not make sense (since to construct, you need to know the type). Furthermore (in c++), calling virtual functions from a constructor does not work (as the derived class's vtable part has not been set up). If one thinks about it carefully, allowing virtual functions to be called from a contructor opens up a can of worms (such as what if virtual functions of derived classes are called prior to member initialization).
As far as destructors are concerned, at the point of destruction, the vtable is "intact", and we (c++ runtime) are fully aware of the type (so to speak). The destructor of the most derived part of the type is found (if virtual, through vtable), and therefore that destructor, and naturally that of all bases can be called.
How are virtual destructors handled internally? I mean the link
Virtual Destructors illustrates the concept but my question is how the
vptr of both the vtables (Derived and Base) are called?
Destructors are handled the same as normal virtual functions (that is, there addresses are looked up in a vtable if they are virtual at the expense of one (perhaps 2?) extra level/s of indirection). Furthermore, c++ guarantees that all base destructors shall execute (in opposite order of construction which relies on order of declaration) after completion of a derived destructor.
One can mimick/simulate virtual construction by using patterns such as the prototype pattern (or cloning), or by using factories. In such cases either an instance of the real type exists (to be used polymorphically), or a factory exists (deriving from abstract factory), that creates a type (via virtual function) based on some knowledge provided.
Hope this helps.
I assume we have a Base class A, and it's derived B.
1.: You can delete B via an A pointer, and then the correct method is to call the B destructor too.
However, you just can't say, that a B object should be created while you actually just call the A constructor. There is just not such a case.
You can say:
A* a = new B ();
or
B b;
But both directly call the B's constructor.
2.: Well, i am not entirely sure, but i guess it will iterate through the relevant part of the class hierarchy, and search for the closest call of the function. If a function is not virtual, it stop iterating and call it.
3.: You should always use virtual destructor, if you want to inherit something from that class. If it's a final class, you shouldn't.
I wasted a couple of days trying to discover why my derived virtual destructors were not being called before discovering the answer so hopefully I can save other a lot of grief with this reply.
I started using derived classes three and four levels deep in my project. Virtual functions seemed to work fine but then I discovered I had massive memory leaks because my destructors were not being called. No compiler or runtime error - the destructors just were not being called.
There is a ton of documentation and examples about this on the web but none of it was useful because my syntax was correct.
I decided that if the compiler wasn't going to call my destructors, I needed to create my own virtual destruct method to call. Then I got the compiler error that solved the problem - "class if a Forward Reference". Adding an include for the derived class header files in the base class solved the problem. The compiler needs the class definition to call the destructor!
I suggest when creating a new derived class, include the header file in the base and intermediate classes. Probably also a good idea to add conditional debug code to your destructors to check that they are bing called.
Bob Rice
In the code below, b is a base-class pointer. However, when I invoke the destructor (either explicitly or implicitly via delete), the derived class destructor is invoked first. I don't understand how this works. There could be any number of derived classes, each with their own destructors. How can the compiler know which derived class destructor to invoke from the base destructor?
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() { cout << "Base destructor" << endl; }
};
class Derived : public Base {
public:
~Derived() { cout << "Derived destructor" << endl; }
};
int main(int argc, char * argv[]) {
Base * b = new Derived();
b->~Base(); // delete b; has the same result
}
dynamic binding, the compiler doesn't decide, the runtime does because the destructor is virtual. C++ destruction calls the destructor on the current class and implicitly calls the parent class until it hits the base class.
The call to virtual destructor works the same as a call to any other virtual function, as a result of virtual dispatch via virtual table. Apart from this,
b->~Base(); // delete b; "has the same result"
this is not true, because delete also frees the memory, which you haven't done here. delete b calls a destructor for *b and deallocates raw memory to operating system. You have only destroyed the building but haven't given ground back.
This is done the same way as virtual functions. Its called dynamic binding. When non virtual member functions are resolved statically means at compile-time, virtual members are resolved dynamically means during run time. Compiler maintains a vtable for this. If the object has one or more virtual functions, the compiler puts a hidden pointer in the object called a "virtual-pointer" or "v-pointer." This v-pointer points to a global table called the "virtual-table" or "v-table.". Read more in details from here.
It doesn't. It happens the other way around. Normal virtual function despatching calls the derived destructor, and the derived destructor calls the base destructor.
Note: My first answer was so off-base that I deleted it. It was so far off-base that someone should have down voted my response. This is another try.
In the opening post, master_latch asked:
How can the compiler know which derived class destructor to invoke from the base destructor?
How this happens is implementation specific.
Why this has to happen is "because the standard says so." Here's what the standard says:
C++11 12.4 paragraph 5:
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 non-variant members, the destructors for X’s direct base classes and, if X is the type of the most derived class, 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. A return statement 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.
C++11 12.4 paragraph 10:
In an explicit destructor call, the destructor name appears as a ~ followed by a type-name or decltype-specifier that denotes the destructor’s class type. The invocation of a destructor is subject to the usual rules for member functions, ...
The example code in C++11 12.4 paragraph 10 indicates the intent of the above:
struct B {
virtual ~B() { }
};
struct D : B {
~D() { }
};
D D_object;
B* B_ptr = &D_object;
void f() {
D_object.B::~B(); // calls B’s destructor
B_ptr->~B(); // calls D’s destructor
...
}
master_latch, your example of using b->~Base(); is identical to the second call in the example code. Think of b->~Base(); as if it meant b->__destruct_me(). It is in a sense no different than a call to any other virtual function.
A compliant implementation has to do this because "because the standard says so." How an implementation does it? The standard doesn't say. (That's good requirementese, by the way. Say what has to be done, but don't say how to do it.)
Most implementations (every implementation I have poked into) do this by generating multiple functions for a destructor. One function implements the body of the destructor as specified by the programmer. A wrapper destructor executes this body of the destructor function, then destroys non-static data members in reverse order of construction, and then invokes parent class destructors. That classes can virtually inherit from some parent class adds another twist. This means that a third destructor function for a given class might be needed.
So how does an implementation know that b->~Base() should call the wrapper destructor for class Derived? Dynamically casting a pointer to a polymorphic class to a void* pointer yields a pointer to the most derived object.
C++11 5.2.7 paragraph 7:
If T is “pointer to cv void,” then the result is a pointer to the most derived object pointed to by v. Otherwise, a run-time check is applied to see if the object pointed or referred to by v can be converted to the type pointed or referred to by T.
In other words, dynamically casting a polymorphic pointer to void* yields a pointer to the object as it was declared or allocated. The virtual table (not a part of the standard) dictates how to find the destructor. The implementation ensures that the pointer to the virtual table can be determined from a void* pointer to the most derived object. This is what lets the implementation know which destructor to call. From that point on, the pointer to that most derived object is no longer a void* pointer.
I understand why I am getting the error I am getting (pure virtual function called). I am trying to call pure virtual functions from within the destructor of my base class shown below. However, I do not know how to rework my code to prevent this from happening. Here are the base and derived classes (the relevant portions anyway):
Base class:
TailFileManager::TailFileManager(const std::string &filename, const int fileOpenPeriod_ms)
: m_Stop(false)
{
m_WorkerThread.reset(new boost::thread(boost::bind(&TailFileManager::TailFile, this, filename, fileOpenPeriod_ms)));
}
TailFileManager::~TailFileManager()
{
m_Stop = true;
m_WorkerThread->join();
}
void TailFileManager::TailFile(const std::string &filename, const int fileOpenPeriod_ms)
{
std::ifstream ifs(filename.c_str());
while (! ifs.is_open())
{
boost::this_thread::sleep(boost::posix_time::milliseconds(fileOpenPeriod_ms));
ifs.open(filename.c_str());
}
ifs.seekg(0, std::ios::end);
while (! m_Stop)
{
ifs.clear();
std::string line;
while (std::getline(ifs, line))
{
OnLineAdded(line);
}
OnEndOfFile();
}
ifs.close();
}
Derived class:
ETSLogTailFileManager::ETSLogTailFileManager(const std::string &filename, const int heartbeatPeriod_ms)
: TailFileManager(filename, heartbeatPeriod_ms),
m_HeartbeatPeriod_ms(heartbeatPeriod_ms),
m_FoundInboundMessage(false),
m_TimeOfLastActivity(0)
{
}
ETSLogTailFileManager::~ETSLogTailFileManager()
{
}
void ETSLogTailFileManager::OnLineAdded(const std::string &line)
{
// do stuff...
}
void ETSLogTailFileManager::OnEndOfFile()
{
// do stuff...
}
You shouldn't call virtual functions during construction or destruction, because the calls won't do what you think, and if they did, you'd still be unhappy. If you're a recovering Java or C# programmer, pay close attention to this Item, because this is a place where those languages zig, while C++ zags.
Re-work your design i.e you may call some cleanup function before object get destroyed, idea is just avoid virtual function during const/dest (if there are any!), if you are working with C++...
The rules for virtual invocation are different. C++ 2003, section 12.7 "Construction and Destruction", says:
Lets refresh some old memories ...
Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from a destructor, and the object to which the call applies is the object under construction or destruction, the function called is the one defined in the constructor or destructorâs own class or in one of its bases, but not a function overriding it in a class derived from the constructor or destructorâs class, or overriding it in one of the other base classes of the most derived object (1.8). If the virtual function call uses an explicit class member access (5.2.5) and the object-expression refers to the object under construction or destruction but its type is neither the constructor or destructorâs own class or one of its bases, the result of the call is undefined.
Because of this difference in behavior, it is recommended that you never invoke an object's virtual function while it is being constructed or destroyed.
Never Call Virtual Functions during Construction or Destruction
An Excerpt from Effective C++, Third Edition
by Scott Meyers
June 6, 2005
http://www.artima.com/cppsource/nevercall.html
As far as the C++ standard is concerned:
if you call a virtual function in a constructor or destructor, then the function is
dynamically dispatched as if its dynamic type were that of the current constructor/destructor being executed (§12.7/4)
if that function happened to a pure virtual, then this is undefined behavior (§10.4/6); the Itanium ABI defines the behavior: __cxa_pure_virtual is called.
So, you have a bit of a thorny issue...
A possible solution to the problem would be to break it down in two parts, in order to break the destruction in two parts. This could be achieved with a Strategy pattern:
provide a customizable interface, your strategy
provide a manager class that encapsulate the functionality and defers to the strategy for the customizable parts
Let's make it clearer:
class Interface {
public:
friend class Manager;
private:
virtual void finalize() = 0;
}; // class Interface
class Manager {
public:
explicit Manager(std::unique_ptr<Interface>&&);
~Manager();
private:
std::unique_ptr<Interface> _interface;
}; // class Manager
Manager::~Manager() {
_interface->finalize();
}
The trick ? At the point where finalize() is called the destruction of _interface has not begun yet! The call to the destructor will happen later; and thus you do not suffer from a half-dead object's fate.
I'll end this answer by a warning about join-ing a thread in a destructor now. Beware that destructors are automatically called in case of stack unwinding, it might therefore be dangerous to wait indefinitely while failing; especially if the thread is waiting for data that should be provided by the currently being unwound one... a classic case of dead-lock.
References (n3337):
§12.7/4 Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class.
§10.4/6 Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined.
You write,
“I am trying to call pure virtual functions from within the destructor of my base class shown below.”
And the code in question is
TailFileManager::~TailFileManager()
{
m_Stop = true;
m_WorkerThread->join();
}
Happily in a single-threaded execution this couldn't possibly call a pure virtual function. But the thread that you're joining might call a pure virtual function on this object, possibly via a non-virtual member function. If so, then the issue is with the threading, specifically the lifetime management of this object.
Unfortunately you do not show the relevant code. Try to reduce things to a small, complete, working example. Where "working" in the sense that it reproduces the problem.
Depending on what system you're on this may work:
Set a breakpoint on the pure function call handler: __cxa_pure_virtual.
This worked for me using gdb: break __cxa_pure_virtual then, when the breakpoint was hit, up showed my code that was busted. (In my case, I am introducing a second thread and destruction was currently happening on a different thread while the object was being used.)
Documentation of __cxa_pure_virtual: https://www.swag.uwaterloo.ca/acd/docs/ItaniumC++ABI.htm#pure-virtual
From 10.4 Abstract Classes parag. 6 in the Standard :
"Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined."
Assuming that a call to a non-pure virtual function from a constructor (or destructor), is allowed by the Standard, why the difference ?
[EDIT] More standards quotes about pure virtual functions:
§ 10.4/2 A virtual function is specified pure by using a pure-specifier (9.2) in the function declaration in the class definition. A pure virtual function needs be defined only if called with, or as if with (12.4), the qualified-id syntax (5.1). ... [ Note: A function declaration cannot provide both a pure-specifier and a definition —end note ]
§ 12.4/9 A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined.
Some questions that need answering are:
Where the pure virtual function has not been given an implementation, should this not be a compiler or linker error instead?
Where the pure virtual function has been given an implementation, why can it not be well-defined in this case to invoke this function?
Because a virtual call can NEVER call a pure virtual function -- the only way to call a pure virtual function is with an explicit (qualified) call.
Now outside of constructors or destructors, this is enforced by the fact that you can never actually have objects of an abstract class. You must instead have an object of some non-abstract derived class which overrides the pure virtual function (if it didn't override it, the class would be abstract). While a constructor or destructor is running, however, you might have an object of an intermediate state. But since the standard says that trying to call a pure virtual function virtually in this state results in undefined behavior, the compiler is free to not have to special case things to get it right, giving much more flexibility for implementing pure virtual functions. In particular, the compiler is free to implement pure virtuals the same way it implements non-pure virtuals (no special case needed), and crash or otherwise fail if you call the pure virtual from a ctor/dtor.
I think this code is an example of the undefined behaviour referenced by the standard. In particular, it is not easy for the compiler to notice that this is undefined.
(BTW, when I say 'compiler', I really mean 'compiler and linker'. Apologies for any confusion.)
struct Abstract {
virtual void pure() = 0;
virtual void foo() {
pure();
}
Abstract() {
foo();
}
~Abstract() {
foo();
}
};
struct X : public Abstract {
virtual void pure() { cout << " X :: pure() " << endl; }
virtual void impure() { cout << " X :: impure() " << endl; }
};
int main() {
X x;
}
If the constructor of Abstract directly called pure(), this would obviously be a problem and a compiler can easily see that there is no Abstract::pure() to be called, and g++ gives a warning. But in this example, the constructor calls foo(), and foo() is a non-pure virtual function. Therefore, there is no straightforward basis for the compiler or linker to give a warning or error.
As onlookers, we can see that foo is a problem if called from the constructor of Abstract. Abstract::foo() itself is defined, but it tries to call Abstract::pure and this doesn't exist.
At this stage, you might think that the compiler should issue a warning/error about foo on the grounds that it calls a pure virtual function. But instead you should consider the derived non-abstract class where pure has been given an implementation. If you call foo on that class after construction (and assuming you haven't overriden foo), then you will get well-defined behaviour. So again, there is no basis for a warning about foo. foo is well-defined as long as it isn't called in the constructor of Abstract.
Therefore, each method (the constructor and foo) are each relatively OK if you look on them on their own. The only reason we know there is a problem is because we can see the big picture. A very smart compiler would put each particular implementation/non-implementation into one of three categories:
Fully-defined: It, and all the methods it calls are fully-defined at every level in the object hierarchy
Defined-after-construction. A function like foo that has an implementation but which might backfire depending on the status of the methods it calls.
Pure virtual.
It's a lot of work to expect a compiler and linker to track all this, and hence the standard allows compilers to compile it cleanly but give undefined behaviour.
(I haven't mentioned the fact that it is possible to give implementations to pure-virtual methods. This is new to me. Is it defined properly, or is it just a compiler-specific extension? void Abstract :: pure() { })
So, it's not merely undefined 'because the standard says so`. You have to ask yourself 'what behaviour would you define for the above code?'. The only sensible answer is either to leave it undefined or to mandate a run-time error. The compiler and linker won't find it easy to analyse all these dependencies.
And to make matters worse, consider pointers-to-member-functions! The compiler or linker can't really tell if the 'problematic' methods will ever be called - it might depend on a whole load of other things that happen at runtime. If the compiler sees (this->*mem_fun)() in the constructor, it can't be expected to know how well-defined mem_fun is.
It is the way the classes are constructed and destructed.
Base is first constructed, then Derived. So in the constructor of Base, Derived has not yet been created. Therefore none of its member functions can be called. So if the constructor of Base calls a virtual function, it can't be the implementation from Derived, it must be the one from Base. But the function in Base is pure virtual and there is nothing to call.
In destruction, first Derived is destroyed, then Base. So once again in the destructor of Base there is no object of Derived to invoke the function, only Base.
Incidentally it is only undefined where the function is still pure virtual. So this is well-defined:
struct Base
{
virtual ~Base() { /* calling foo here would be undefined */}
virtual void foo() = 0;
};
struct Derived : public Base
{
~Derived() { foo(); }
virtual void foo() { }
};
The discussion has moved on to suggest alternatives that:
It might produce a compiler error, just like trying to create an instance of an abstract class does.
The example code would no doubt be something like:
class Base
{
// other stuff
virtual void init() = 0;
virtual void cleanup() = 0;
};
Base::Base()
{
init(); // pure virtual function
}
Base::~Base()
{
cleanup(); // which is a pure virtual function. You can't do that! shouts the compiler.
}
Here it is clear what you are doing is going to get you into trouble. A good compiler might issue a warning.
it might produce a link error
The alternative is to look for a definition of Base::init() and Base::cleanup() and invoke that if it exists, otherwise invoke a link error, i.e. treat cleanup as non-virtual for the purpose of constructors and destructors.
The issue is that won't work if you have a non-virtual function calling the virtual function.
class Base
{
void init();
void cleanup();
// other stuff. Assume access given as appropriate in examples
virtual ~Base();
virtual void doinit() = 0;
virtual void docleanup() = 0;
};
Base::Base()
{
init(); // non-virtual function
}
Base::~Base()
{
cleanup();
}
void Base::init()
{
doinit();
}
void Base::cleanup()
{
docleanup();
}
This situation looks to me to be beyond the capability of both the compiler and linker. Remember that these definitions could be in any compilation unit. There is nothing illegal about the constructor and destructor calling init() or cleanup() here unless you know what they are going to do, and there is nothing illegal about init() and cleanup() calling the pure virtual functions unless you know from where they are invoked.
It is totally impossible for the compiler or linker to do this.
Therefore the standard must allow the compile and link and mark this as "undefined behaviour".
Of course if an implementation does exist, the compiler is free to use it if able. Undefined behaviour doesn't mean it has to crash. Just that the standard doesn't say it has to use it.
Note that this case the destructor is calling a member function that calls the pure virtual but how do you know it will do even this? It could be calling something in a completely different library that invokes the pure virtual function (assume access is there).
Base::~Base()
{
someCollection.removeMe( this );
}
void CollectionType::removeMe( Base* base )
{
base->cleanup(); // ouch
}
If CollectionType exists in a totally different library there is no way any link error can occur here. The simple matter is again that the combination of these calls is bad (but neither one individually is faulty). If removeMe is going to be calling pure-virtual cleanup() it cannot be called from Base's destructor, and vice-versa.
One final thing you have to remember about Base::init() and Base::cleanup() here is that even if they have implementations, they are never called through the virtual function mechanism (v-table). They would only ever be called explicitly (using full class-name qualification) which means that in reality they are not really virtual. That you are allowed to give them implementations is perhaps misleading, probably wasn't really a good idea and if you wanted such a function that could be called through derived classes, perhaps it is better being protected and non-virtual.
Essentially: if you want the function to have the behaviour of a non-pure virtual function, such that you give it an implementation and it gets called in the constructor and destructor phase, then don't define it as pure virtual. Why define it as something you don't want it to be?
If all you want to do is prevent instances being created you can do that in other ways, such as:
- Make the destructor pure virtual.
- Make the constructors all protected
Before discussing why it's undefined, let's first clarify what the question is about.
#include<iostream>
using namespace std;
struct Abstract {
virtual void pure() = 0;
virtual void impure() { cout << " Abstract :: impure() " << endl; }
Abstract() {
impure();
// pure(); // would be undefined
}
~Abstract() {
impure();
// pure(); // would be undefined
}
};
struct X : public Abstract {
virtual void pure() { cout << " X :: pure() " << endl; }
virtual void impure() { cout << " X :: impure() " << endl; }
};
int main() {
X x;
x.pure();
x.impure();
}
The output of this is:
Abstract :: impure() // called while x is being constructed
X :: pure() // x.pure();
X :: impure() // x.impure();
Abstract :: impure() // called while x is being destructed.
The second and third lines are easy to understand; the methods were originally defined in Abstract, but the overrides in X take over. This result would have been the same even if x had been a reference or pointer of Abstract type instead of X type.
But this interesting thing is what happens inside the constructor and destructor of X. The call to impure() in the constructor calls Abstract::impure(), not X::impure(), even though the object being constructed is of type X. The same happens in the destructor.
When an object of type X is being constructed, the first thing that is constructed is merely an Abstract object and, crucially, it is ignorant of the fact that it will ultimately be an X object. The same process happens in reverse for the destruction.
Now, assuming you understand that, it is clear why the behaviour must be undefined. There is no method Abstract :: pure which could be called by the constructor or destructor, and hence it wouldn't be meaningful to try to define this behaviour (except possibly as a compilation error.)
Update: I've just discovered that is possible to give an implementation, in the virtual class, of a pure virtual method. The question is: Is this meaningful?
struct Abstract {
virtual void pure() = 0;
};
void Abstract :: pure() { cout << "How can I be called?!" << endl; }
There will never be an object whose dynamic type is Abstract, hence you'll never be able to execute this code with a normal call to abs.pure(); or anything like that. So, what is the point of allowing such a definition?
See this demo. The compiler gives warnings, but now the Abstract::pure() method is callable from the constructor. This is the only route by which Abstract::pure() can be called.
But, this is technically undefined. Another compiler is entitled to ignore the implementation of Abstract::pure, or even to do other crazy things. I'm not aware of why this isn't defined - but I wrote this up to try to help clear up the question.
I will type an example :
class A
{
public:
virtual ~A(){}
};
class B: public A
{
public:
~B()
{
}
};
int main(void)
{
A * a = new B;
delete a;
return 0;
}
Now in Above Example , destructors will be called recursively bottom to up .
My Question is how Compiler do this MAGIC .
There are two different pieces of magic in your question. The first one is how does the compiler call the final overrider for the destructor and the second one is how does it then call all the other destructors in order.
Disclaimer: The standard does not mandate any particular way of performing this operations, it only mandates what the behavior of the operations at a higher level are. These are implementation details that are common to various implementations, but not mandated by the standard.
How does the compiler dispatch to the final overrider?
The first answer is the simple one, the same dynamic dispatch mechanism that is used for other virtual functions is used for destructors. To refresh it, each object stores a pointer (vptr) to each of its vtables (in the event of multiple inheritance there can be more than one), when the compiler sees a call to any virtual function, it follows the vptr of the static type of the pointer to find the vtable and then uses the pointer in that table to forward the call. In most cases the call can be directly dispatched, in others (multiple inheritance) it calls some intermediate code (thunk) that fixes the this pointer to refer to the type of the final overrider for that function.
How does the compiler then call the base destructors?
The process of destructing an object takes more operations than those you write inside the body of the destructor. When the compiler generates the code for the destructor, it adds extra code both before and after the user defined code.
Before the first line of a user defined destructor is called, the compiler injects code that will make the type of the object be that of the destructor being called. That is, right before ~derived is entered, the compiler adds code that will modify the vptr to refer to the vtable of derived, so that effectively, the runtime type of the object becomes derived (*).
After the last line of your user defined code, the compiler injects calls to the member destructors as well as base destructor(s). This is performed disabling dynamic dispatch, which means that it will no longer come all the way down to the just executed destructor. It is the equivalent of adding this->~mybase(); for each base of the object (in reverse order of declaration of the bases) at the end of the destructor.
With virtual inheritance, things get a bit more complex, but overall they follow this pattern.
EDIT (forgot the (*)):
(*) The standard mandates in §12/3:
When a virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from a destructor, and the object to which the call applies is the object under construction or destruction, the function called is the one defined in the constructor or destructor’s own class or in one of its bases, but not a function overriding it in a class derived from the con- structor or destructor’s class, or overriding it in one of the other base classes of the most derived object.
That requirement implies that the runtime type of the object is that of the class being constructed/destructed at this time, even if the original object that is being constructed/destructed is of a derived type. A simple test to verify this implementation can be:
struct base {
virtual ~base() { f(); }
virtual void f() { std::cout << "base"; }
};
struct derived : base {
void f() { std::cout << "derived"; }
};
int main() {
base * p = new derived;
delete p;
}
A virtual destructor is treated in the same way as any other virtual function. I note that you've correctly maked the base class's destructor as virtual. As such, it is no way different than any other virtual function, as far as dynamic dispatch is concerned. The most derived class destructor gets called through dynamic dispatch but it also automatically results in calls to Base class destructors of the class1.
Most compiler implements this feature using vtable and vptr, though the language specification does not mandate it. There can be a compiler which does this differently, without using vtable and vptr.
Anyway, as it true for most compilers, it is worth knowing what vtable is. So vtable is a table contains pointers of all virtual functions the class defines, and the compiler adds vptr to the class as hidden pointer which points to the correct vtable, so the compiler uses correct index, calculated at compile-time, to the vtable so as to dispatch the correct virtual function at runtime.
1. The italicized text is taken from #Als's comment. Thanks to him. It makes things more clear.
A suitable implementation of (virtual) destructors the compiler might use would be (in pseudocode)
class Base {
...
virtual void __destruct(bool should_delete);
...
};
void Base::__destruct(bool should_delete)
{
this->__vptr = &Base::vtable; // Base is now the most derived subobject
... your destructor code ...
members::__destruct(false); // if any, in the reverse order of declaration
base_classes::__destruct(false); // if any
if(should_delete)
operator delete(this); // this would call operator delete defined here, or inherited
}
This function gets defined even if you didn't define a destructor. Your code would just be empty in that case.
Now all derived classes would override (automatically) this virtual function:
class Der : public Base {
...
virtual void __destruct(bool should_delete);
...
};
void Der::__destruct(bool should_delete)
{
this->__vptr = &Der::vtable;
... your destructor code ...
members::__destruct(false);
Base::__destruct(false);
if(should_delete)
operator delete(this);
}
A call delete x, where x is of pointer to class type, would be translated as
x->__destruct(true);
and any other destructor call (implicit due to variable going out of scope, explicit x.~T()) would be
x.__destruct(false);
This results in
the most derived destructor always being called (for virtual destructors)
operator delete from the most derived object being called
all members' and base classes' destructors being called.
HTH. This should be understandable if you understand virtual functions.
As usual with virtual functions there will be some implementation mechanism (like a vtable pointer) that will let the compiler find which destructor to run first depending on the type of the object. Once the most derived class destructor is run it will in turn run the base class destructor and so on.
It's up to the compiler how to implement it and typically it's done with the same mechanism as other virtual methods. In other words there's nothing special about destructors that requires a virtual method dispatch mechanism that is distinct from that used by normal methods.
A virtual destructor has an entry in the virtual table just as other virtual functions do. When the destructor is invoked -either manually or automatically from a call to delete- the most derived version is invoked. A destructor also automatically calls the destructor for its base classes, so that in combination with the virtual dispatch is what causes the magic.
Unlike other virtual functions, when you override a virtual destructor, your object's virtual destructor is called in addition to any inherited virtual destructors.
Technically this can be achieved by whatever means the compiler chooses, but almost all compilers achieve this via static memory called a vtable, which permits polymorphism on functions and destructors. For each class in your source code, a static constant vtable is generated for it at compile time. When an object of type T is constructed at runtime, the object's memory is initialized with a hidden vtable pointer which points to the T's vtable in ROM. Inside the vtable is a list of member function pointers and a list of destructor function pointers. When a variable of any type that has a vtable goes out of scope or is deleted with delete or delete[], all of the destructor pointers in vtable the object points to are all invoked. (Some compilers choose to only store the most derived destructor pointer in the table, and then include a hidden invocation of the superclass's destructor in the body of every virtual destructor if one exists. This results in equivalent behavior.)
Additional magic is needed for virtual and nonvirtual multiple inheritance. Assume I am deleting a pointer p, where p is of the type of a base-class. We need to invoke the destructor of the sub-classes with this=p. But using multiple inheritance, p and the start of the derived object may not be the same! There is a fixed offset which must be applied. There is one such offset stored in the vtable for each class that is inherited, as well as a set of inherited offsets.
When you have a pointer to an object, it points to a block of memory that has both the data for that object and a 'vtable pointer.' In microsoft compilers, the vtable pointer is the first piece of data in the object. In Borland compilers, it is the last. Either way, it points to a vtable that represents a list of function vectors corresponding to the virtual methods that can be invoked for that object/class. The virtual destructor is just another vector in that list of function pointer vectors.