I know the cases where pure virtual destructors are needed. I also know that If we don't provide an implementation for them it will give me a linker error. What I don't understand is why this should be the case in a code fragment as shown below:
int main()
{
Base * p = new Derived;
}
Here there is no delete, so no call to destructor and so no need for its implementation(assuming it is supposed to behave like other normal functions which are declared but not defined, linker complains only when we call them)...or am I missing something?
I need to understand why this should be a special case?
Edit: based on comments from BoBTFish
Here are my Base and Derived classes
class Base
{
public:
Base(){}
virtual ~Base() = 0;
};
class Derived : public Base
{
};
The compiler tries to build the virtual table given a virtual (pure or not) destructor, and it complains because it can't find the implementation.
virtual destructors differ from other virtual functions because they are called when the object is destroyed, regardless of whether it was implemented or not. This requires the compiler to add it to the vf table, even if it's not called explicitly, because the derived class destructor needs it.
Pedantically, the standard requires a pure virtual destructor to be implemented.
C++11 standard:
12.4 Destructors
Paragraph 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. If a class has a base class with a
virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.
Destructors differ from other virtual functions in this way, because they are special and automatically invoked in bases, with no possible, useful or meaningful way to prevent it.
[C++11: 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. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.
Bases are always destroyed, and to do this, a base destructor definition is required. Conversely, other overridden virtual functions are not invoked automatically at all. Hence the special-case requirement.
struct Base
{
virtual ~Base() = 0; // invoked no matter what
virtual void foo() = 0; // only invoked if `Base::foo()` is called
};
Base::~Base() {}
/* void Base::foo() {} */
struct Derived : Base
{
virtual void foo() { /* Base::foo(); */ }
};
int main()
{
std::unique_ptr<Base> ptr(new Derived());
}
One practical reason is that destructors come first in the list of virtual member functions in the vtable in practically all implementations. And implementations tend to define the vtable itself when it defines the first virtual member function. So, no destructor, no vtable. And the vtable is critical.
Related
Is it wrong to write:
class A {
public:
virtual ~A() = 0;
};
for an abstract base class?
At least that compiles in MSVC... Will it crash at run time?
Yes. You also need to implement the destructor:
class A {
public:
virtual ~A() = 0;
};
inline A::~A() { }
should suffice.
If you derive anything from A and then try to delete or destroy it, A's destructor will eventually be called. Since it is pure and doesn't have an implementation, undefined behavior will ensue. On one popular platform, that will invoke the purecall handler and crash.
Edit: fixing the declaration to be more conformant, compiled with http://www.comeaucomputing.com/tryitout/
Private destructors: they will give you an error when you create an object of a derived class -- not otherwise. A diagnostic may appear though.
12.4 Destructors
6 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.
A class with a pure virtual destructor is an abstract class.
Note well:
10.4 Abstract classes
2 A pure virtual function need 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 ]
Taken straight from the draft:
struct C {
virtual void f() = 0 { }; // ill-formed
};
Scott said on Effective C++, 3rd Edition, pg. 43 that to make an abstract class, we just need to give it a pure virtual destructor:
class AWOV { // AWOV = "Abstract w/o Virtuals"
public:
virtual ~AWOV() = 0; // declare pure virtual destructor
};
Then, he went on said that there is one twist: we must provide a definition for the pure virtual destructor:
AWOV::~AWOW() {} // definition of pure virtual dtor
My question is, by specifiying = 0, for pure virtual functions, we are saying that the function cannot have any definition for the class where this pure virtual function is declared.
Why is it OK to provide a definition (even it is empty) for the pure virtual destructor here?
"we are saying that the function cannot have any definition for the class where this pure virtual function is declared."
That's not what pure virtual means. Pure virtual only means that the containing class cannot be instantiated (is abstract), so it has to be subclassed, and subclasses must override the method. E.g.,
struct A {
virtual ~A() = 0;
};
A::~A() {}
struct B : A {};
int main()
{
A a; // error
B b; // ok
}
Here, the B destructor is implicitly defined. If it was another method that is pure virtual, you'd have to explicitly override it:
struct A {
virtual void foo() = 0;
};
void A::foo() {}
struct B : A {};
int main()
{
B b; // error
}
Providing a definition for a pure virtual method is desirable when the base class must be abstract but still provide some default behavior.
In the specific case of a destructor, it has to be provided because it will be called automatically when subclass instances are destroyed. A program that tries to instantiate a subclass of a class with a pure virtual destructor without a definition will not pass the linker.
Making it pure forces derived (non-abstract) classes to implement their own.
Providing an implementation allows derived classes to invoke base class behavior (which destructors do by default).
There are 2 cases.
Pure virtual destructor
This case is specifically treated by the standard.
12.4 Destructors [class.dtor]
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. If a class has a base class with a
virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.
The case of the destructor is different because all destructors are called in an inheritance hierearchy (assuming correct deletion) in reverse order of construction, even if not explicitly. So the base class destructor is called when the object gets deleted - that's why it needs an implementation.
Pure virtual method
These differ from destructors in that they're not required to be implemented, nor do they need an implementation. The difference for the missing requirement is that when a Derived::foo() gets called, it doesn't automatically call Base::foo() (not that it could, since it can or can not be implemented).
Why you would want to implement a pure virtual method depends on the case. I look at the pure specifier as a hint to the programmer, as opposed to related to the logic. It tells you - the programmer - that you should implement that method. It doesn't really matter if the base class has an implementation or not.
by specifiying = 0, for pure virtual functions, we are saying that the function cannot have any definition for the class where this pure virtual function is declared.
Not really. You're saying derived non-abstract classes have to override that function. This doesn't prevent you from implementing it yourself.
This is not necessary for all pure virtual functions. Not at all.
This way, the derived classes will still be forced to override the implementation, but there will be a default implementation in the base class, in case you need to call it. And that's the case here - because you're dealing with a destructor: when a derived object is being destroyed, its destructor is called and its base classes destructors are called as well. That's why you need an implementation for A::~A.
By making a function pure virtual we force the user of the class to replace the function with another in the derived class.
The base class function can still be called with BaseClass::myfunction(...)
Now the base class might want to provide some core functionality that the derived class may use if it chooses to do so.
Correct answer:
Suppose there are 2 pure virtual functions in class. Now assume that both have implementation. The reason for providing implementation for PVF is that the Base class method can act as default behavior if Base class is derived by child by implementing these PVF methods(to make class as concrete)
The pure virtual destructor in base class should have a definition. Otherwise compiler will generate a call to base class destructor from the derived class destructor during link-time and will cause a link-error.
I tried to define the pure virtual destructor inside the base class like below:
class base
{
public:
base()
{
cout << "constructor in base class\n";
}
virtual ~base()=0
{}
};
This gave the compilation error:
error: pure-specifier on function-definition
Then i tried to define the function outside the base class like below:
class base
{
public:
base()
{
cout << "constructor in base class\n";
}
virtual ~base()=0;
};
base::~base()
{
}
This removes the compilation error and it behaves as my understanding.
But my question is how does defining the pure virtual destructor outside the base class removes the compilation error?
Your second example is correct.
A lot of the other answers assume that it is illegal to have a pure virtual function with a default implementation, however that is incorrect.
In the case of a pure virtual destructor you must have a definition (see the link in xmoex answer).
It is true that:
§10.4/2 a function declaration cannot provide both a pure-specifier
and a definition
However, as you noticed it possible to provide a definition outside of the declaration.
i looked at this page:
http://www.gotw.ca/gotw/031.htm
and from my understanding a pure virtual destructor must have a definition (even an empty one) as every derived class has to call the base classes destructor
It is invalid syntax to write:
virtual ~base()=0
{}
If you want to supply implementation of a pure virtual member function, you should do it outside of the class. Most of the time you should not do this, since pure virtual functions should never be called anyhow. It is however possible to define implementation for pure virtual functions.
In fact, a pure virtual destructor must have an implementation. This is because destructors of all base classes are called on object destruction regardless of whether destructor in a given class is pure virtual or not.
Thus, if you create an instance of any of the classes derived from base then at some point destructors of all classes to which the object belongs will be called including the base::~base() destructor. If you do not define it, the linker will not find a required symbol and will complain.
The destructor is the only method that even if it is pure virtual, has to have an implementation in order for the class it's defined in to be useful. So in contrast to #Kiril's answer I would say that pure virtual functions can have implementations.
Somewhat off topic :
struct base {
virtual void func() = 0;
};
void base::func() { /* default implementation */ }
class derived : public base{
void func() { base::func(); } // have to explicitly call default implementation.
};
Pure virtual methods can have implementations, but they make the base class abstract and force deriving classes to overwrite those methods.
Say you have a pointer member in the base class. You want to delete it on the destructor but also make the class abstract - so you implement to pure virtual destructor.
This is an implementation detail - the fact that the destructor is implemented should't be visible from the outside.
Compiler is giving link error and require to provide definition for Base pure virtual destructor.
class Base
{
public:
virtual ~Base() = 0;
};
class Derived : public Base
{
public:
virtual ~Derived(){ std::cout << "Derived dtor"; }
};
int main()
{
Derived d;
}
Just provide an empty implementation for it (outside the class definition):
Base::~Base() { }
Being pure-virtual just means that you must override the member function in any concrete derived class; it doesn't mean that it cannot have a body. In the case of the destructor, you must supply a body, wether the destructor is pure-virtual or not, since it is invoked by the compiler when you destroy the object.
Just to be clear, you must provide an implementation. Whether it is empty or not is up to you. This is because the compiler generates code that calls the destructor whenever you try to destroy an instance of Base. You could declare a normal virtual Base:
virtual ~Base();
And never define it. This would be fine as long as you never destroy an instance of Base (questionable conduct, but it would work). However, in your case, Base has a Derived type, which calls the Base class's destructor in its own destructor. That's where your linker error is coming from.
Yes. There's a non-virtual call of Base::~Base, implicitly from Derived::~Derived. Therefore the compiler is right to complain that Base::~Base must be defined, even if empty.
Since Derived inherits Base, destroying a Derived object will first call Derived::~Derived and then Base::~Base (the compiler does this for you - whether you like it or not).
Hence, you have to provide an implementation for Base::~Base. Note that this isn't particularly strange. A pure virtual function can have an implementation. 'pure virtual' only means that the class cannot be instantiated.
Is it wrong to write:
class A {
public:
virtual ~A() = 0;
};
for an abstract base class?
At least that compiles in MSVC... Will it crash at run time?
Yes. You also need to implement the destructor:
class A {
public:
virtual ~A() = 0;
};
inline A::~A() { }
should suffice.
If you derive anything from A and then try to delete or destroy it, A's destructor will eventually be called. Since it is pure and doesn't have an implementation, undefined behavior will ensue. On one popular platform, that will invoke the purecall handler and crash.
Edit: fixing the declaration to be more conformant, compiled with http://www.comeaucomputing.com/tryitout/
Private destructors: they will give you an error when you create an object of a derived class -- not otherwise. A diagnostic may appear though.
12.4 Destructors
6 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.
A class with a pure virtual destructor is an abstract class.
Note well:
10.4 Abstract classes
2 A pure virtual function need 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 ]
Taken straight from the draft:
struct C {
virtual void f() = 0 { }; // ill-formed
};