2016-07-13 14 views
1
#include <iostream> 
using namespace std; 

/* 
* base class 
*/ 
class A 
{ 
public: 
    A() 
    { 
     this->init(); 
    } 

    virtual void init() 
    { 
     cout << " A"; 
    } 
    // in public, so class B can call it. 
    void testit() 
    { 
     this->init(); 
    } 
}; 

/* 
* child class 
*/ 
class B : public A 
{ 
public: 
    B() 
    { 
     this->init(); 
    } 

    virtual void init() 
    { 
     // here get segmentation fault. 
     // but if call A::init() then it is ok. 
     A::testit(); 
     // if call A::init(); then it working. 
     cout << "B" ; 
    } 

}; 

int main() 
{ 

     B b; 
     A * a = &b; 
     // here B virtual function will be called. 
     a->init(); 
     return 0; 

} 

これは基本的に仮想関数テストです。しかし、子クラス呼び出しの基本クラスが独自の仮想関数の中で機能するとき、それはランタイムセグメンテーションフォールトを取得しました。どうして?なぜ仮想関数がセグメンテーションフォルトを与えるのですか

実行時にA :: testit()からセグメンテーションフォルトが発生すると、 なぜですか?

子インスタンスのコールベース関数がエラーになるのはなぜですか?

答えて

1
// but if call A::init() then it is ok. 
A::testit(); 

あなたはA::testit()init()を呼んでいます。 init()が仮想の場合、B::init()は、現在の実際のオブジェクトがBのときに再帰的に呼び出され、最後は無限再帰になります。

A::init()と明示的に無限の再帰を呼び出すと回避されますが、それは問題ありません。

1

要するに、セグメンテーションフォールトは、無限の再帰によるものです。 B::initA::testitを呼び出し、オブジェクトのinitを呼び出します。オブジェクトはクラスBであるため、A::testitB::initを呼び出し、A::testitなどを無期限に呼び出します。

なぜこれを行い、A::initを明示的に呼び出さないのですか?まあ、それは多型の一例です。この状況では、B::initの内側のthisポインタは、クラスBのオブジェクトの方を指しています。 BAの仮想initメソッドを上書きしたため、そのオブジェクトのinitを呼び出すと、上書きメソッドBが呼び出されます。したがって、B::init()は、A::testit()を呼び出しています。これは、無限ループでB::init()を呼び出します。親のバージョンinitを呼び出すには、明示的に呼び出す必要があります(A::init)。

+1

オブジェクトの 'init'メソッドが' A'のコンストラクタまたはデストラクタの内部で呼び出されたとき、 'B :: init'は呼び出されません。これは 'this'ポインタがその段階で' B'クラスのオブジェクトを指していないので、 'A'クラスのオブジェクトを指しているので、' init'を呼び出すと 'A :: init'代わりに。多態性は、コンストラクタとデストラクタの派生クラスへの仮想メソッド呼び出しをディスパッチしません。派生クラスはこれらのステージに存在しないためです。 –

0

返信ありがとう、Remy Lebeauが指摘したのと同じように、 多態性がコンストラクタ内で機能していません。しかし、私はまだこの場合のように困惑しています:

#include <iostream> 
using namespace std; 

class A 
{ 
    public: 
    A() 
    { 
     print(); 
    } 

    A(A* a) 
    {   
     cout << "A ctor call " << endl; 
     a->print();   
    } 

    virtual void print() 
    { 
     cout << "A" << endl; 
    } 

}; 

class B : public A 
{ 
    public: 
    B():A(this),_a(new A(this)) 
    { 
     cout << "B ctor call " << endl; 
     _a->print(); 
    } 

    B(int i):_a(new A(this)), A(this) 
    { 
     cout << "B ctor call " << endl; 
     _a->print(); 
    } 

    virtual void print() 
    { 
     cout << "B" << endl; 
    } 

    private: 
    A * _a; 
}; 


int main() 
{ 
    B b; 
    cout << "init second instance but same result as before " << endl; 
    B b2(1); 
    A * a = &b; 
    a->print(); 
    a = &b2; 
    a->print(); 
} 

and result is like: 

A ctor call 
A 
A ctor call 
B 
B ctor call 
A 
init second instance but same result as before 
A ctor call 
A 
A ctor call 
B 
B ctor call 
A 
B 
B 

したがって、Bコンストラクタが呼び出されたときにわかります。それ自身のこのポインタはBaseクラスAへのパスです。 多態性を初めて渡すだけではディスパッチされません。 すぐに2番目に渡します。 なぜですか?

関連する問題