#include <iostream> using namespace std; class CPolygon { protected: int width, height; public: virtual int area () { return (0); } }; class CRectangle: public CPolygon { public: int area () { return (width * height); } };
Has compilation warning
Class '[C@1a9e0f7' has virtual method 'area' but non-virtual destructor
How to understand this warning and how to improve the code?
[EDIT] is this version correct now? (Trying to give answer to elucidate myself with the concept)
#include <iostream> using namespace std; class CPolygon { protected: int width, height; public: virtual ~CPolygon(){}; virtual int area () { return (0); } }; class CRectangle: public CPolygon { public: int area () { return (width * height); } ~CRectangle(){} };
Deleting a derived class object using a pointer of base class type that has a non-virtual destructor results in undefined behavior.
A C++ class containing virtual member functions has a non-virtual destructor. Since this class has virtual member functions, it will be used as a base class.
Calling virtual functions from a constructor or destructor is considered dangerous most of the times and must be avoided whenever possible. All the C++ implementations need to call the version of the function defined at the level of the hierarchy in the current constructor and not further.
Virtual keyword for destructor is necessary when you want different destructors should follow proper order while objects is being deleted through base class pointer.
If a class has a virtual method, that means you want other classes to inherit from it. These classes could be destroyed through a base-class-reference or pointer, but this would only work if the base-class has a virtual destructor. If you have a class that is supposed to be usable polymorphically, it should also be deletable polymorphically.
This question is also answered in depth here. The following is a complete example program that demonstrates the effect:
#include <iostream> class FooBase { public: ~FooBase() { std::cout << "Destructor of FooBase" << std::endl; } }; class Foo : public FooBase { public: ~Foo() { std::cout << "Destructor of Foo" << std::endl; } }; class BarBase { public: virtual ~BarBase() { std::cout << "Destructor of BarBase" << std::endl; } }; class Bar : public BarBase { public: ~Bar() { std::cout << "Destructor of Bar" << std::endl; } }; int main() { FooBase * foo = new Foo; delete foo; // deletes only FooBase-part of Foo-object; BarBase * bar = new Bar; delete bar; // deletes complete object }
Output:
Destructor of FooBase Destructor of Bar Destructor of BarBase
Note that delete bar;
causes both destructors, ~Bar
and ~BarBase
, to be called, while delete foo;
only calls ~FooBase
. The latter is even undefined behavior, so that effect is not guaranteed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With