C.121: If a base class is used as an interface, make it a pure abstract class
- Reason
A class is more stable (less brittle) if it does not contain data. Interfaces should normally be composed entirely of public pure virtual functions and a default/empty virtual destructor.Example
public:
// ...only pure virtual functions here ...
virtual ~My_interface() {} // or =default
};
Example, bad
class Goof {
public:
// ...only pure virtual functions here ...
// no virtual destructor
};
class Derived : public Goof {
string s;
// ...
};
void use()
{
unique_ptr<Goof> p {new Derived{"here we go"}};
f(p.get()); // use Derived through the Goof interface
g(p.get()); // use Derived through the Goof interface
} // leak
The Derived is deleted through its Goof interface, so its string is leaked. Give Goof a virtual destructor and all is well.
-
Enforcement
Warn on any class that contains data members and also has an overridable (non-final) virtual function that wasn’t inherited from a base class. -
相关Items:
Effiective C++ 3rd edition.Item 7: Declare destructors virtual in polymorphic base classes.
C++ Coding Standards: 101 Rules, Guidelines, and Best PracticesItem 50: Make base class destructors public and virtual, or protected and nonvirtual.
Reason from stackoverflow
Virtual destructors are useful when you might potentially delete an instance of a derived class through a pointer to base class:
class Base
{
// some virtual methods
};
class Derived : public Base
{
~Derived()
{
// Do some important cleanup
}
};
Here, you'll notice that I didn't declare Base's destructor to be virtual
. Now, let's have a look at the following snippet:
Base *b = new Derived();
// use b
delete b; // Here's the problem!
Since Base's destructor is not virtual
and b
is a Base*
pointing to a Derived
object, delete b
has undefined behaviour:
[In
delete b
], if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.
In most implementations, the call to the destructor will be resolved like any non-virtual code, meaning that the destructor of the base class will be called but not the one of the derived class, resulting in a resources leak.
To sum up, always make base classes' destructors virtual
when they're meant to be manipulated polymorphically.
If you want to prevent the deletion of an instance through a base class pointer, you can make the base class destructor protected and nonvirtual; by doing so, the compiler won't let you call delete
on a base class pointer.
You can learn more about virtuality and virtual base class destructor in this article from Herb Sutter.
网友评论