[英]Understanding static_cast
我在理解下面的代碼時遇到了一些問題。 為什么我可以調用c()函數?
#include <iostream>
#include <list>
using namespace std;
class A
{};
class B : public A
{
public:
void c() { cout << "c: B" << ++x << endl; }
int x;
};
int main(void) {
class A *a = new A();
static_cast<B*>(a)->c();
return 0;
}
輸出是:
constr A
c: B1
這是因為未定義的行為可能會產生意想不到的結果,包括看起來可行。
任何事情都可能發生,這是未定義的行為。 實際上可能發生的情況是B::c()
使用了B::x
會被存儲在B
實例中的位置,緊接着A
子對象1 。 並且它將覆蓋屬於其他對象的內存。 在您的情況下,該值以前為0
並變為1
,但是它可能是該位置的真實所有者放置在其中的任何值。
(1)如果編譯器實現空基類優化,則B::x
和B::A
子對象實際上可能重疊。
如果您問為什么編譯器不能阻止它,那是因為您已經使用static_cast
覆蓋了類型檢查。 在所有類型轉換中,只有dynamic_cast
注意對象的真實類型,甚至很容易破壞。
您正在以非常不安全的方式編寫兩個定義明確的操作。
B
對象,編譯器也無法阻止您將A*
強制轉換為B*
,因為B*
對於單獨再次強制轉換非常有用。 B*
訪問B
成員。 問題是,您將此“偽” B*
用於其他類型,而不是轉換回其真實類型。
dynamic_cast可以提供有關成功或失敗的信息(如果您具有至少一個虛擬函數,而我假設您的真實程序會擁有),而static_cast則不能。 static_cast不使用運行時類型標識。 進行強制轉換是有正當理由的,但是您需要遵守規則以避免未定義的行為。
向下轉換時,首選動態投放而不是靜態投放。 當然,我不知道為什么有人會用繼承而不是一個虛擬函數來編寫程序(除非這只是一個簡單的演示問題的例子),但是這樣做可能有用例或原因。 http://en.cppreference.com/w/cpp/language/dynamic_cast
如果絕對必須使用static_cast,則需要遵循有關何時使用的規則。 不幸的是,static_cast不會為您提供異常或失敗通知,因此必須謹慎使用。 http://en.cppreference.com/w/cpp/language/static_cast
2)如果new_type是指向某個類D的指針或引用,而表達式的類型是指向其非虛擬基數B的指針或引用,則static_cast執行向下轉換。 這種static_cast不會進行任何運行時檢查以確保對象的運行時類型實際上是D,並且只有在通過其他方式(例如實現靜態多態性)保證了此前提條件的情況下,才可以安全地使用該對象。 安全下調可以通過dynamic_cast完成。
為了解決您的示例為何起作用的問題,請允許我引用ANSI std。
1.3.24 [defns.undefined]未定義的行為,本國際標准沒有規定任何要求的行為[注:當本國際標准省略任何明確的行為定義或程序使用錯誤的構造或錯誤的數據時,可能會出現未定義的行為。 允許的未定義行為的范圍從完全忽略具有無法預測結果的情況到在以環境特征的書面方式在翻譯或程序執行過程中表現為行為(帶有或不帶有診斷消息),終止翻譯或執行(帶有發布)診斷消息)。 許多錯誤的程序構造不會導致未定義的行為; 他們需要被診斷。 —尾注]
隨時避免進行強制轉換-這通常意味着出了點問題。
在您的示例中,您試圖將一個對象轉換為具有更多可處理的能力。
這就像對某人說這輛車是一輛貨車,指向一輛車。
當Trabant到達而不是貨車時,它會流下眼淚
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.