2013-06-26 65 views
1

我有以下代碼(來自virtual functions and static_cast被盜):static_cast如何影響虛函數調用?

#include <iostream> 

class Base 
{ 
public: 
    virtual void foo() { std::cout << "Base::foo() \n"; } 
}; 

class Derived : public Base 
{ 
public: 
    virtual void foo() { std::cout << "Derived::foo() \n"; } 
}; 

如果我有:

int main() 
{ 
    Base base; 
    Derived& _1 = static_cast<Derived&>(base); 
    _1.foo(); 
} 

打印輸出將是:Base::foo()

但是,如果我有:

int main() 
{ 
    Base * base; 
    Derived* _1 = static_cast<Derived*>(base); 
    _1->foo(); 
} 

打印輸出將b e:Segmentation fault: 11

老實說,我都不太明白。根據上面的例子,有人可以解釋static_cast和虛擬方法之間的複雜性嗎?順便說一句,如果我想打印輸出爲「Derived::foo()」,我該怎麼辦?

+8

如果您對未初始化的指針進行調用,分段錯誤實際上是最好的結果。 –

+0

要打印輸出爲Derived :: foo(),您需要確保Derived類型的實例存在,但在任何示例中都不存在。 – mungflesh

+0

由於您沒有任何實際的對象,因此您使用指針進行segfault。只是指針,還沒有指向任何。所以'_1-> foo()'試圖從一個隨機內存位置讀取虛擬表。如果您將指針更改爲'Base base;派生* _1 = static_cast (&base);'然後你可以嘗試調用'foo()',但你仍然應該得到'Base :: foo()',因爲那是對象。你需要一個'Derived _2; _2.foo()'。 – John

回答

4

在你的第二個例子中,你segfault因爲你沒有instanciate你的基指針。所以沒有v-table可以調用。嘗試:

Base * base = new Base(); 
Derived* _1 = static_cast<Derived*>(base); 
_1->foo(); 

這將打印基地:: foo的()

的問題是沒有意義的,因爲的static_cast不會影響v表。但是,這使得非虛函數更敏感:

class Base 
{ 
public: 
    void foo() { std::cout << "Base::foo() \n"; } 
}; 

class Derived : public Base 
{ 
public: 
    void foo() { std::cout << "Derived::foo() \n"; } 
}; 


int main() 
{ 
    Base base; 
    Derived& _1 = static_cast<Derived&>(base); 
    _1.foo(); 
} 

這將輸出Derived :: foo()。然而,這是一個非常錯誤的代碼,雖然它編譯,行爲是undefined

+1

這個例子仍然被破壞。當源引用不是指向一個[sub]對象時,將'Base&'強制轉換爲'Derived& 'Derived'類型,在你的例子中行爲是不確定的 – AnT

+0

它可能是非法的,是的,我猜它是未定義的,所以也許它在答案中沒有它的位置,但是可以問自己爲什麼這樣做會編譯並給出這個儘管如此,我會編輯答案,thx。 – lip

2

虛擬函數的全部目的是變量的靜態類型應該不重要。編譯器將查找對象本身的實際實現(通常在對象內隱藏一個vtable指針)。 static_cast應該沒有影響。

4

指針或引用類型的有效static_cast根本不影響虛擬調用。根據對象的動態類型解析虛擬調用。 static_cast指針或引用不會更改實際對象的動態類型。

雖然您在示例中觀察到的輸出不相關。這些例子很簡單。

第一個使無效static_cast。在底層對象不是Derived的情況下,您不得將Base &轉換爲Derived &。任何嘗試執行此類轉換都會導致未定義的行爲。

下面是引用類型的static_cast有效的應用程序的向下轉換

int main() 
{ 
    Derived derived; 
    Base &base = derived; 
    Derived& _1 = static_cast<Derived&>(base); 
    _1.foo(); 
} 

在第二個例子中的代碼是完全打破了什麼都沒有做任何類型轉換或虛擬調用原因的例子。該代碼試圖操縱未初始化的指針 - 行爲是未定義的。

2

在這兩個示例中,行爲都是未定義的。A Base對象不是Derived對象,並且告訴編譯器假裝它不是一個對象。獲取代碼以打印出"Derived::foo()"的方法是使用Derived類型的對象。