Skip to content

Destructor and inheritance

对于OOP,思考destructor和inheritance之间的关系是非常重要的,下面是一些主题:

Invokation order of destructor in a class hierarchy

本节标题的含义是:在一个class hierarchy中,destructor的调用次序。

与本节相关的内容有:

1、C++\Language-reference\Classes\Subtype-polymorphism\Inheritance\Pure-virtual-function-and-abstract-class\Pure-virtual-method-called

Destructor and polymorphism

本节的内容基于stackoverflow When to use virtual destructors?整理的:

Make base classes' destructors virtual

To sum up, always make base classes' destructors virtual when they're meant to be manipulated polymorphically.

这部分内容主要在Virtual destructor中介绍。

简单地说就是:允许继承,并且允许runtime polymorphism。

Make the base classes' destructor protected and nonvirtual

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 deleteon a base class pointer.

简单地说就是:允许继承,但是不允许runtime polymorphism。

在 wikipedia Curiously recurring template pattern#Object counter中列举了这样的例子,在C++\Idiom\Templates-and-generic-programming\Curiously-recurring-template-pattern中收录了这篇文章:

Object counter:

#include <iostream>

template<typename T>
struct counter
{
    static int objects_created;
    static int objects_alive;

    counter()
    {

        ++objects_created;
        ++objects_alive;
        std::cout << __PRETTY_FUNCTION__ << " " << objects_created << " " << objects_alive << std::endl;
    }

    counter(const counter&)
    {

        ++objects_created;
        ++objects_alive;
        std::cout << __PRETTY_FUNCTION__ << " " << objects_created << " " << objects_alive << std::endl;
    }
protected:
    ~counter() // objects should never be removed through pointers of this type
    {
        --objects_alive;
        std::cout << __PRETTY_FUNCTION__ << " " << objects_created << " " << objects_alive << std::endl;
    }
};
template<typename T> int counter<T>::objects_created(0);
template<typename T> int counter<T>::objects_alive(0);

class X: counter<X>
{
    // ...
};

class Y: counter<Y>
{
    // ...
};

int main()
{
    {
        X x1, x2, x3, x4, x5;
    }
    {
        Y y1, y2, y3, y4, y5;
    }
}
// g++ test.cpp

NOTE: 上述程序的输出:

counter<T>::counter() [with T = X] 1 1
counter<T>::counter() [with T = X] 2 2
counter<T>::counter() [with T = X] 3 3
counter<T>::counter() [with T = X] 4 4
counter<T>::counter() [with T = X] 5 5
counter<T>::~counter() [with T = X] 5 4
counter<T>::~counter() [with T = X] 5 3
counter<T>::~counter() [with T = X] 5 2
counter<T>::~counter() [with T = X] 5 1
counter<T>::~counter() [with T = X] 5 0
counter<T>::counter() [with T = Y] 1 1
counter<T>::counter() [with T = Y] 2 2
counter<T>::counter() [with T = Y] 3 3
counter<T>::counter() [with T = Y] 4 4
counter<T>::counter() [with T = Y] 5 5
counter<T>::~counter() [with T = Y] 5 4
counter<T>::~counter() [with T = Y] 5 3
counter<T>::~counter() [with T = Y] 5 2
counter<T>::~counter() [with T = Y] 5 1
counter<T>::~counter() [with T = Y] 5 0

它这样做的原因是:

避免直接使用counter类对象,让counter类为abstract class,因为它是一个mixin class。

What are practical uses of a protected constructor? # A

When a class is (intended as) an abstract class, a protected constructor is exactly right. In that situation you don't want objects to be instantiated from the class but only use it to inherit from.

There are other uses cases, like when a certain set of construction parameters should be limited to derived classes.

最最典型的例子就是上面的mixin class counter

https://stackoverflow.com/questions/5150748/protected-constructor-and-accessibility/5150944

Make the destructor public and nonvirtual

典型的例子就是STL的container,它们这样的目的是避免STL的用户继承其中的class。在维基百科Standard Template Library中对此进行了说明:

STL containers are not intended to be used as base classes (their destructors are deliberately non-virtual); deriving from a container is a common mistake.

Guideline: destructor of any base class must be public and virtual or protected and non-virtual

在cppreference virtual function specifier#Virtual destructor中提及了这个。