2014-05-19 58 views
-6
#include <iostream> 
using namespace std; 
class Person 
{ 
public: 
     void P(){ cout << "Person P" << endl; } 
     virtual void Print(){ cout << "Person Print" << endl; } 
     Person(){ cout << "Constructor Person" << endl; } 
     virtual ~Person(){ cout << "Dectructor Person" << endl; } 
}; 
class Developer : public Person 
{ 
public: 
     void Pi() { cout << "Developer Pi" << endl; } 
     void Print() override 
     { 
       cout << "Developer Print" << endl; 
     } 
     Developer(){ cout << "Constructor Develoeper" << endl; } 
     ~Developer(){ cout << "Dectructor Develoer" << endl; } 
}; 
int main() 
{ 
     Person *p = new Person(); 
     Developer* d = dynamic_cast<Developer*>(p); 
     d->Pi(); 

     delete p; 
     delete d; 
    return 0; 
} 

輸出:派生類的方法,無需構造

Constructor Person 
Developer Pi 
Dectructor Person 

爲什麼我可以調用Developer的功能Pi

如何在不使用Developer的構造函數的情況下調用Pi

請注意,Pi只在類別Developer中聲明。

+0

你可以做任何你想做的事情,但會導致**未定義的行爲** – Rakib

+0

請看這個非常全面的答案爲什麼這是UB:http://stackoverflow.com/a/2474021/3549027 – dlf

回答

3

你不行。你的代碼有一個未定義的行爲。如果我修改main()功能:

int main() 
{ 
    Person *p = new Person(); 
    Developer* d = dynamic_cast<Developer*>(p); 
    assert(d!=0); 
    d->Pi(); 

    delete p; 
    delete d; 
    return 0; 
} 

然後斷言d!=0被觸發。這表明dynamic_cast失敗。您在空指針上調用Developer::Pi,並使用您的編譯器,它運行正常,可能是因爲Developer::Pi不使用this

+1

@irineau,這不是OP的答案。如果沒有'assert'代碼的工作,並且令人驚訝地調用'Pi',問題就是爲什麼 – Rakib

2

Developer* d = dynamic_cast<Developer*>(p);
您有d == nullptr

d->Pi(); 你調用未定義行爲:

方法一般相當於是其採取額外this爲參數,當你不使用this的方法似乎在你的情況下工作的功能。

0

這是因爲dynamic_cast。您不是指實例中的任何變量,因此它不會失敗。

訪問任何虛擬方法或訪問將存儲在對象中的任何內容都會導致訪問衝突。

0

通過聲明d是一個指向Developer類的對象的指針,您可以向編譯器提供提示。您還聲明void Pi()不是虛擬的,因此編譯器使用了早期綁定(編譯時)。這意味着被調用函數的地址在編譯過程中被鎖定,並且不需要對象進行評估(與虛擬方法不同)

當調用d-> Pi()時,它與您的相同'用Pi調用Pi(d)指向Developer實例的指針。在MFC中有一種方法稱爲驗證或類似的東西,它使用相同的機制來檢查你的指針是否爲空:)

你不會碰到刪除d,因爲它是在標準的,刪除一個空指針是OK,並且什麼也不做(刪除一個髒指針是不確定的)。

只需將虛擬字添加到Pi方法簽名中,或者向Developer類中添加一個字段並嘗試在Pi方法中對該字段進行修改。你會看到不同之處;)