2012-04-28 60 views
3

我偶然發現一個實例,其中有一個函數將一個指向基本類型的指針,然後我需要將其上傳到派生類型以訪問某些附加功能。但是,dynamic_cast失敗了,這很奇怪,因爲我的類型明確地繼承了基類型。動態轉換堆棧對象失敗

要到發生了什麼事情的底部,我創建了下面的測試程序,我想複製我所看到的:

void cast(TestClass *baseType) 
{ 
    if (dynamic_cast<Derived *>(baseType)) 
     TRACE("cast was sucessful"); 
    else 
     TRACE("cast failed"); 
} 

int main(int argc, char *argv[]) 
{ 
    Derived *test1 = new Derived(); 
    TestClass *test2 = new TestClass(); 
    TestClass test3; 

    test1->identify(); // prints: this is a Derived class 
    test2->identify(); // prints: this is a TestClass 

    cast(test1); // succesful 
    cast(test2); // fail - expected 

    // reassign test2 to test1 
    test2 = test1; 
    test2->identify(); // prints: this is a Derived class 

    cast(test2); // succesful 

    // the interesting part, the test3 object (created on stack), does not cast 
    // despite that it would seem possible from the cast method. 
    test3 = *test1; 
    test3.identify(); // prints: this is a TestClass 
    cast(&test3); // fails? 

    return a.exec(); 
} 

這是有趣的,因爲如果你提出只用我稱爲cast()的方法,你會期望它可以投入傳入的對象。我已經證明,情況並非如此;它取決於對象最初是如何創建的。令人困惑的是,爲什麼可以投放一個已經被引用而不是按價值重新分配的對象。此外,會使用static_cast工作,只要我們保證類型兼容?

回答

7

test3TestClass類型(我認爲它是Derived的父類),所以動態轉換失敗。

即使您將*test1指定給它,該作業只會複製TestClass部件(也稱爲slicing)。將指針指向指針時,不會發生切片。

你可以認爲派生對象的同時,他們的基地的一部分:

*test1: 
|--------------| 
|TestClass part| 
|--------------| 
|Derived part | 
|--------------| 

test3: 
|--------------| 
|TestClass part| 
|--------------| 

當您將指針(test2=test1),對象本身不會改變,要通過不同的,只要看一眼玻璃(通過指向TestClass的指針),從而鑄造工程。

當你分配對象本身(test3=*test1),目標(test3)有房只爲TestClass對象,所以拷貝帶走多餘Derived部分。

+0

非常明確的答案。謝謝。所以一旦一個實例被切片,就沒有辦法「恢復」派生類型了? – user975326 2012-04-28 17:51:33

+0

@ user975326 - 正確。請注意,您可以使用引用而不是類型,它在這方面會像指針一樣工作,但語法與使用堆棧分配對象相同。 – Attila 2012-04-28 17:55:08