2012-08-10 106 views
5

讓我們來看看下面的代碼:如何通過基類指針調用派生類的虛函數

class CBase 
{ 
public: 
    virtual vfunc() { cout << "CBase::vfunc()" << endl; } 
}; 

class CChild: public CBase 
{ 
public: 
    vfunc() { cout << "CChild::vfunc()" << endl; } 
}; 

int main() 
{ 
CBase *pBase = new CBase; 
((CChild*)pBase)->vfunc(); // !!! important 
delete pBase; 
return 0; 
} 

輸出是:

CBase::vfunc() 

但我希望看到:CChild :: vfunc()

顯式((CChild *)pBase)強制類型爲「CChild *」。那麼爲什麼要調用派生的vfunc()我需要替換「重要的」字符串: ((CChild *)pBase) - > CChild :: vfunc();

回答

6

這不是它的工作原理 - 這就是:

CBase *pBase = new CChild; 
pBase->vfunc(); 

virtual函數調用指針上的動態解析&引用(除非你明確地調用該方法,像你這樣)。這意味着它不會告訴編譯器指針是什麼,它會在vftable中查找方法。在你的情況下,這是vftableCBase

5

你不能。 *pBaseCBase類型的對象。你不能把它當作是CChild,因爲它不是CChild對象。

將演員獲得的指針用於CChild*會導致您的程序顯示未定義的行爲。

+1

所以如何理解Schildt H .:「基類指針也可以用作指向從該基類派生的任何類的對象的指針」。 – LEXX 2012-08-10 19:00:51

+0

爲什麼字符串((CChild *)pBase) - > CChild :: vfunc()的工作原理? – LEXX 2012-08-10 19:06:32

+0

@LEXX:首先,您應該刻錄該書並獲得[一本好的入門書](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list)。不過,他在該報價中所說的話是正確的。基類指針('CBase *')可以指向從'CBase'派生的類型的對象(如'CChild')。但這並不是你所做的:你的基類指針指向一個基類對象。例如,如果你有'CBase * p = new CChild();',那麼'p'將是一個指向派生類的對象的基類指針。 – 2012-08-10 19:32:33

2

其他答案提出了重要的要點 - 補充:如果您實際上可能正在處理CChild(例如,它是作爲參數傳遞的參考),則可以使用dynamic_cast向下轉換。然而,高度依賴dynamic_cast往往表明您的設計出了問題。

上投細節可以在這裏找到: http://msdn.microsoft.com/en-us/library/cby9kycs(v=vs.80).aspx

所以這個過程將需要通過dynamic_cast鑄造CBase參數CChild,如果引用是CChilddynamic_cast成功,那麼你可以肯定你是處理CChild,然後您可以安全地將其用作CChild

0

這裏的問題看起來很簡單。 CBase不能神奇地升級到CChild!讓我重寫你的例子並添加一些評論。這應該是不言而喻的......

#include <iostream> 

class CBase { 
public: 
    virtual void vfunc() { std::cout << "CBase::vfunc()" << std::endl; } 
    virtual ~CBase(){} // Virtual destructor... extremely important! I'll let you figure out why as an excercise 
}; 

class CChild: public CBase { 
public: 
    void vfunc() { std::cout << "CChild::vfunc()" << std::endl; } 
    ~CChild(){} // Is this destructor called? When? Try adding some std::cout to each destructor 
}; 

int main() 
{ 
    CBase *ptr1 = new CBase; 
    CBase *ptr2 = new CChild; 

    ptr1->vfunc(); // ptr1 points to an instance of CBase. This is what's important!! 
    ptr2->vfunc(); // ptr2 points to an instance of CChild, which can be referenced to as a CBase 

    delete ptr1; 
    delete ptr2; 
} 

輸出:

CBase::vfunc() 
CChild::vfunc() 

PS:我才意識到我是5年左右遲到了,但因爲我在這,我覺得教育價值」反正它會發布!

相關問題