2238


C++でポリモーフィズムを使用する際、基底クラスのデストラクタをvirtualにする必要があるということはよく言われることですが、派生クラスのデストラクタもvirtualとして宣言しておくべきかどうか悩んでいます。

派生クラスのデストラクタも仮想関数でなければならない時というのはどういう時でしょうか。逆に仮想関数じゃなくても良い(vtableへのコストからしないほうがよい場合)時というのはどういう時か、という事も併記して頂けるととても助かります。


CC BY-SA 3.0
2014-12-20T10:04:10.820
2235
2017-07-23T05:56:40.920
3069
question
c++
派生クラスのデストラクタにもvirtualが必要な時はどういう時か?


基底クラスのデストラクタがvirtualなら、派生クラスのデストラクタにもそれが伝播して自動的にvirtualになります。  
回答としては「気にしなくてもいい」だと思いますが、明示するためにvirtualと書いておいた方がいいかもしれません。


CC BY-SA 3.0
2014-12-20T10:32:00.973
2237
2014-12-20T10:32:00.973
3277
2235
answer


基底クラスのデストラクタをvirtualにすると自動的にその派生クラスのデストラクタもvirtualになります。  
デストラクタに限らず基底クラスでvirtualと宣言した関数は派生クラスでvirtualと宣言しようとしまいとvirtualとして扱われます。

本家SOの似た質問のリンクを貼っておきます。  
[Are virtual destructors
inherited?](https://stackoverflow.com/questions/2198379/are-virtual-
destructors-inherited)

**追記**  
一応仕様書を抜粋しておきます。

ISO/IEC 14882:1998(E)より

> 10.3 Virtual functions  
>  2 If a virtual member function vf is declared in a class Base and in a
> class Derived, derived directly or indirectly  
>  from Base, a member function vf with the same name and same parameter  
>  list as Base::vf is declared, then Derived::vf is also virtual  
>  (whether or not it is so declared) and it overrides Base::vf.
>
> 12.4 Destructors  
>  7 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.


CC BY-SA 3.0
2014-12-20T10:32:35.377
2238
2014-12-20T14:58:29.720
2017-05-23T12:38:56.467
-1
4765
2235
answer


`virtual`は派生クラスへ伝播するので、基底クラスのデストラクタが`virtual`であれば、派生クラスのデストラクタも`virtual`となります。

[code]

    #include <iostream>
    
    class Base
    {
      public:
        virtual ~Base()
        {
          std::cout << "~Base()" << std::endl;
        }
    };
    
    class Derived : public Base
    {
      public:
        ~Derived()
        {
          std::cout << "~Derived()" << std::endl;
        }
    };
    
    class MoreDerived : public Derived
    {
      public:
        ~MoreDerived()
        {
          std::cout << "~MoreDerived()" << std::endl;
        }
    };
    
    int main()
    {
      Base* b = new MoreDerived();
      delete b;
      return 0;
    }
    
[/code]

の出力結果は

[code]

    ~MoreDerived()
    ~Derived()
    ~Base()
    
[/code]

となります。

しかし、以下の記事によれば、ごく一部のコンパイラによっては問題があるかもしれないとのことで、例えば`armcc`は派生クラスのデストラクタに`virtual`を付けないと警告を出すようです。

[override - C++ "virtual" keyword for functions in derived classes. Is it
necessary? - Stack
Overflow](https://stackoverflow.com/questions/4895294/c-virtual-keyword-for-
functions-in-derived-classes-is-it-necessary)


CC BY-SA 3.0
2014-12-20T10:32:46.637
2239
2014-12-20T10:32:46.637
2017-05-23T12:38:55.250
-1
3313
2235
answer


> 派生クラスのデストラクタもvirtualとして宣言しておくべきかどうか

古いコンパイラも動作対象として考慮に入れるならば、宣言しておいたほうが良いでしょう。

> 派生クラスのデストラクタも仮想関数でなければならない時というのはどういう時でしょうか。

基底クラスのデストラクタが仮想関数の時は常に、です。 昔のコンパイラには、 派生クラスの方にも `virtual` を書かなければ仮想関数にならなかったり、
エラーや警告を出したりするものがありました。 しかしそれでは不便ということで、 最近のコンパイラは自動で仮想関数として扱うようになったのでしょう。

> 逆に仮想関数じゃなくても良い(vtableへのコストからしないほうがよい場合)時というのはどういう時か

現在では、あるとは考えにくいです。

重要なポイントは、 「派生クラスのデストラクタが仮想関数でなければならない理由」ではなく、
「基底クラスのデストラクタが仮想関数でなければならない理由」の方です。

基底クラスのデストラクタが仮想関数でなければならないのは、 ご存知だと思いますが、 **派生クラスとして`new` したものを、
(アップキャストして)基底クラスとして正しく `delete` するため**です。 この時、派生クラスのデストラクタだけ非仮想化するのは、
再派生される可能性などを考えると、ほぼ意味がありません。

もちろん `private` 派生するなども考えられますが、 外側から見て基底クラスとしては扱えなくなりますし、
そんな手段を取る合理的理由は考えにくいのではないでしょうか。


CC BY-SA 3.0
2014-12-20T12:54:15.607
2248
2014-12-20T12:54:15.607
208
2235
answer


基底クラスでデストラクタが仮想ならば派生クラスでも仮想になるのは他の回答者のおっしゃる通りです。  
ポリモーフィズム的に使うつもりはないが、public継承することは前提の基底クラスに関しては、仮想でないデストラクタをprotectedにする、というテクニックがあるようです。これなら危険を回避できます。


CC BY-SA 3.0
2017-07-21T05:20:56.177
36557
2017-07-23T05:56:40.920
2017-07-23T05:56:40.920
24517
24517
2235
answer