0

私のコードでは、3 つのクラスを使用しました。以下の実装を参照してください。

class Medicine 
{ 
   int a;
}

class Pain:public Medicine 
{
   int b;
}

class Comb:public Pain   
{
    string salt,com;
}

すべてのクラスには、パラメーター化されたコンストラクターがあります。そしてcall()、のようです

call()
{
     cout<<"You are in class the_name_of_the_class"<<endl;
}

call()それらのすべてで、同じ名前の関数を定義しました。(今まで仮想として宣言されていません)

コードは次のようになります。

int main()
{       
    Pain *p[2];
    p[0]= new Comb("Salt","Com",2,110);
    p[1]= new Comb("SALT","COM",1,100);

    p[0]->call();

    delete p[0];
    delete p[1];
    return 0;
}

出力: 呼び出しはペインの call() に行きます

ただし、Pain::call() を仮想 (Medicine::call() は実在) にすると、呼び出しは Comb の call() に移動します。問題ない!

Medicine *p[2]しかし、代わりにやっているとPain *p[2]、次のエラーが発生しています

*** glibc detected *** ./a.out: free(): invalid pointer: 0x00000000022ed078 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3b64a760e6]
./a.out[0x400efe]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x3b64a1ecdd]
./a.out[0x400b79]
======= Memory map: ========

より多くのことがここに行き、これはで終わります

Abort(core dumped)

なんでそうなの?これは、Medicine::call() に virtual を使用すると再び消えます。(この問題は、Pain::call() が virtual であるかどうかとは関係ありません)。なぜこうなった?

4

3 に答える 3

0

Scott Mayers の「Effective C++」によると、プログラムで派生クラスを定義する場合は、基本クラスでデストラクタを virtual として定義する必要があります。そうしないと、実行時にプログラムの動作が異なります (おそらくメモリ リーク、間違った出力、クラッシュ)。

于 2013-08-21T12:31:23.073 に答える
0

仮想デストラクタは、基本クラスへのポインタを介して派生クラスのインスタンスを削除できる場合に役立ちます。

class Base 
{
   // some code
};

class Derived : public Base
{
    ~Derived()
    {
        // some code
    }
}

ここでは、Base のデストラクタが仮想であることを宣言しませんでした。それでは、次のコードを見てみましょう。

Base *b = new Derived();
// use b
delete b; // Here's the problem!

Base のデストラクタは仮想ではなく、b は Derived オブジェクトを指す Base* であるため、delete b の動作は未定義です。私の実装でも、デストラクタへの呼び出しは非仮想コードと同様に解決されます。つまり、基本クラスのデストラクタは呼び出されますが、派生クラスのデストラクタは呼び出されず、リソース リークが発生します。また、継承を使用している場合は、有用であるかどうかに関係なく、デストラクタを virtual として宣言することは常に安全です。

于 2013-08-22T05:34:44.700 に答える