2016-07-13 23 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時,B::init()將被遞歸調用,並且最後變爲無限遞歸。

如果你打電話A::init()明確無限遞歸將避免那會沒事的。

1

總之,分段錯誤是由於無窮遞歸。 B::init調用A::testit,它調用對象的init。由於該對象屬於B類,因此這意味着A::testit將會調用B::init,這將會調用A::testit,等等無休無止。

它爲什麼這樣做,不叫A::init明確?那麼,這是一個多態的例子。在這種情況下,B::init內的this指針指向B類的對象。由於B已覆蓋A的虛擬init方法,給該對象的init任何電話都將調用B被覆蓋的方法。所以B::init()呼叫A::testit(),這呼叫B::init()在一個無限循環。要調用父母的版本init,您必須明確地調用它(A::init)。

+1

需要注意的是,當對象的'init'方法在'A'的構造函數或析構函數內被調用時'B :: init'不會被調用。這是因爲'this'指針在這些階段沒有指向類「B」的對象,而是指向類「A」的對象,所以對'init'的任何調用都會調用'A :: init'代替。多態性不派遣構造函數和析構函數中的派生類的虛方法調用,因爲派生類不存在於這些階段。 –

0

感謝您的回覆,就像雷米勒博指出, 多態性是不是裏面的構造工作。但我仍然不解,因爲這種情況:

#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構造函數被調用。它自己的這個指針是傳給基類A的, 並且只有第一次傳遞多態性沒有被調度,然後立即 ,第二次傳遞它的工作。 爲什麼?