#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(){}
};
クラスに仮想メソッドがある場合、それは他のクラスがそれから継承することを意味します。これらのクラスは、基底クラス参照またはポインターを介して破棄できますが、基底クラスに仮想デストラクタがある場合にのみ機能します。多態的に使用できるはずのクラスがある場合は、多態的にも削除できるようにする必要があります。
この質問にも詳細に回答します 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
のみを呼び出すことに注意してください。後者は偶数 未定義の動作 であるため、その効果は保証されません。
つまり、仮想メソッドを持つ基本クラスの仮想デストラクタが必要です。
struct Foo {
virtual ~Foo() {}
virtual void bar() = 0;
};
そのままにする は 未定義の動作につながる可能性があり、通常、valgrindなどのツールでメモリリークとして表示されます。
それは単にそのようなコードが
CPolygon* p = new CRectangle;
delete p;
...または、CPolygonは削除時にポリモーフィックではなく、CRectangeパーツは適切に破棄されないため、スマートポインターへのラップは基本的に正しく動作しません。
CRectangleおよびCPolygon polymorphicalyを削除しない場合、その警告は意味がありません。