web-dev-qa-db-ja.com

C ++のコンパイル中に「仮想メソッドはあるが、非仮想デストラクタ」という警告はどういう意味ですか?

#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); }
  };

コンパイル警告があります

Class '[C@1a9e0f7' has virtual method 'area' but non-virtual destructor

この警告を理解する方法とコードを改善する方法は?

[編集]このバージョンは現在正しいですか? (コンセプトを自分自身で解明するために答えようとする)

#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(){}
  };
38
qazwsx

クラスに仮想メソッドがある場合、それは他のクラスがそれから継承することを意味します。これらのクラスは、基底クラス参照またはポインターを介して破棄できますが、基底クラスに仮想デストラクタがある場合にのみ機能します。多態的に使用できるはずのクラスがある場合は、多態的にも削除できるようにする必要があります。

この質問にも詳細に回答します here 。以下は、効果を示す完全なサンプルプログラムです。

#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
}

出力:

Destructor of FooBase
Destructor of Bar
Destructor of BarBase

delete bar;は、~Bar~BarBaseの両方のデストラクタが呼び出されるのに対し、delete foo;~FooBaseのみを呼び出すことに注意してください。後者は偶数 未定義の動作 であるため、その効果は保証されません。

77
Björn Pollex

つまり、仮想メソッドを持つ基本クラスの仮想デストラクタが必要です。

struct Foo {
  virtual ~Foo() {}
  virtual void bar() = 0;
};

そのままにする  未定義の動作につながる可能性があり、通常、valgrindなどのツールでメモリリークとして表示されます。

14
Tom Kerr

それは単にそのようなコードが

CPolygon* p = new CRectangle;
delete p;

...または、CPolygonは削除時にポリモーフィックではなく、CRectangeパーツは適切に破棄されないため、スマートポインターへのラップは基本的に正しく動作しません。

CRectangleおよびCPolygon polymorphicalyを削除しない場合、その警告は意味がありません。

2