2017-12-07 7 views
-2

を使用して、私は次のクラスとオブジェクトがあるとします。動物は抽象クラスであることどのように適切に削除ポインタへの抽象クラスに

#include <iostream> 

class Animal 
{ 
public: 
    virtual void makeNoise() = 0; 

    void eat() 
    { 
     std::cout << "Eating..." << "\n"; 
    } 

    void sleep() 
    { 
     std::cout << "Sleeping..." << "\n"; 
    } 
}; 

class Cat: public Animal 
{ 
public: 
    void makeNoise() 
    { 
     std::cout << "Miow..." << "\n"; 
    } 
}; 

class Cow: public Animal 
{ 
public: 
    void makeNoise() 
    { 
     std::cout << "Mooo..." << "\n"; 
    } 
}; 

int main() 
{ 
    Animal *animal; 
    Cat *cat = new Cat(); 
    Cow *cow = new Cow(); 

    animal = cat; 
    animal->eat(); 
    animal->sleep(); 
    animal->makeNoise(); 

    animal = cow; 
    animal->eat(); 
    animal->sleep(); 
    animal->makeNoise(); 

    return 0; 
} 

注意。

ポインタを正しく削除するにはanimalcatcow

私はdelete animal;にしようとすると、私は次の警告メッセージが出ます:

警告: 非仮想デストラクタを持つ抽象クラスタイプ「動物」が削除対象が未定義の動作を引き起こします。一方で

私はdelete cat;しようとすると、私は次のメッセージが出ます:

警告: 非仮想デストラクタを持つポリモーフィッククラスタイプ「猫」が削除対象が未定義の動作を引き起こす可能性があります。

+2

警告として「Animal」デストラクタを 'virtual'にします。 – user0042

答えて

1

基本的なC++ルールでは、デストラクタは、派生クラスから基本クラスへの道を切り開いています。 Catが破壊されると、最初にCatの部分が破壊され、その後Animalの部分が破壊されます。

delete animal;は、C++破壊ルールを正しく実行するために、実行時にAnimalベースパートより前に破棄する必要がある派生クラスパートを知っていなければならないため、未定義の動作です。 virtualデストラクタはまさにこれを行います。これにより、破棄が設計通りに機能するようにする動的なディスパッチメカニズムが可能になります。

あなたはvirtualデストラクタを持っていませんが、delete animalは意味がありません。正しい派生クラスのデストラクタを呼び出す方法はなく、Animal部分だけを破棄することは、まさに意味のある動作ではありません。

したがって、C++言語は、このような状況で何が起こるかについては何も想定していません。

あなたのコンパイラは、これについて警告するのに十分です。


delete catでは、状況が多少異なります。 catポインタの静的型はではなく、Animal*であるため、派生クラスのデストラクターが最初に呼び出す動的ディスパッチ機構がなくても明らかです。

コンパイラはこれについて警告していますが、別の言い回し( "原因"と "原因")で警告します。その理由は、Cat自体がvirtualの関数を持つクラス階層の一部であるので、より多くの派生クラスの基本クラスになる可能性があると私は信じています。

delete catが本当に無害であることを確認するために、より完全なコード分析を実行することは明らかです。


この問題を解決するためには、Animalデストラクタvirtualを作ります。あなたがそれをしている間は、生ポインタをstd::unique_ptrに置き換えてください。自分のようなクラスの場合は、依然としてvirtualデストラクタルールに従わなければなりませんが、手動でdeleteを実行する必要はありません。

0

これはまさにコンパイラが警告するものです。クラスごとに独自のデストラクタを定義して実装し、継承のためにvirtualと定義されていることを確認する必要があります。

関連する問題