2017-02-16 23 views
2

仮想関数の動作の例を見ていきます。このテストコードでは、その動作についていくつか質問があります。仮想関数のシグネチャの不一致とその動作

class A 
{ 
public: 
    A(int x) 
    { 
     cout << "In A Constructor" << endl; 
     print(); 
    } 
    ~A(){ 
     cout << "In A Destructor" << endl; 
     delete _val; 
    } 
    virtual void print() { cout << "A." << endl; } 
private: 
    char* _val; 
}; 

class B: public A 
{ 
public: 
    B(int x, int y) : A(x) 
    { 
     _dVal = new char[y]; 
     cout << "In B Constructor 1" << endl; 
     print(); 
    } 
    B() : A(0) 
    { 
     _dVal = new char[1]; 
     cout << "In B Constructor 2" << endl; 
     print(); 
    } 
    ~B(){ 
     cout << "In B Destructor" << endl; 
     delete _dVal; 
    } 
    void print() { cout << "B" << endl; } 
private: 
    char* _dVal; 
}; 

int main(int argc, char** argv) { 
    A* p1 = new B(); 
    p1->print(); 
    delete p1; 
    return 0; 
} 

出力である:

In A Constructor 
A. 
In B Constructor 2 
B 
B 
In A Destructor 

1)なぜ印刷は、クラスBのために呼ばれるクラスAは、仮想関数として示すのみであり、それは(間接参照によって呼び出されている場合 - > )? 2)コンストラクタが実際に呼び出されている場合、Bのデストラクタが呼び出されないのはなぜですか?

+1

ファンクションが基本クラスで仮想である場合、それはすべての派生クラスでも仮想です。デストラクタの同上。 –

+1

1つにつき1つ質問してください。 –

答えて

4

1)クラスAが仮想関数としてそれを表しており、逆参照( - >)によって呼び出されているのはなぜですか?

これは、仮想機能が想定していることです。ポインタp1はタイプA*ですが、実際にはタイプBのオブジェクトを指しています。また、この動的バインディングは、派生クラスが基本クラスへのポインタまたは参照を使用して処理される場合にのみ発生します。

派生クラスのオーバーライド関数もvirtual(キーワードvirtualが宣言に使用されているかどうかにかかわらず)です。

2)コンストラクタが実際に呼び出されている場合、Bのデストラクタが呼び出されないのはなぜですか?あなたはvirtual destructorとして基底クラス(すなわちA::~A)のデストラクタを宣言していないので、

Bのデストラクタが呼び出されません。この場合の動作は未定義です。 Bのコンストラクタは、new B()で明示的にBを構成するために呼び出されます。

+0

興味深い。動作は未定義であるため、クラスBの_dValがoprhanになり、メモリリークが発生する可能性がありますか? – w0ffen

+0

@ user49096あなたが観察した結果から、はい。それは不確定であることに注意してください、何でも可能です。 – songyuanyao

+0

@ user49096 "_動作が定義されていないので、意味はありますか?"いいえ、何が起こるかは定義されていない、未定義、未知... – curiousguy