2014-12-05 80 views
-3

爲什麼dynamic_cast<new>(old)變更olddynamic_cast更改原始對象?

示例代碼:

#include <iostream> 
#include <string> 

class MyInterface { 
public: 
    virtual void say() = 0; 
    virtual ~MyInterface() { } 
}; 

class SubInterface : public MyInterface { 
public: 
    std::string test = "test"; 
    virtual void say() = 0; 
    virtual ~SubInterface() { } 
}; 

class Example : public SubInterface { 
public: 
    void say() { 
    std::cout << test << std::endl; 
    } 
}; 


int main() { 
    MyInterface* ex1 = new Example(); 
    SubInterface* ex2 = dynamic_cast<SubInterface*>(ex1); 
    if (ex2 != nullptr) { 
    std::cout << "call ex2->say(): "; 
    ex2->test = "something else"; 
    ex2->say(); 
    } 
    else { 
    std::cout << "error" << std::endl; 
    } 

    std::cout << "call ex1->say(): "; 
    ex1->say(); 

    std::cerr << "debug: ex1=" << ex1 << "; ex2=" << ex2 << std::endl; 

    return 0; 
} 

,其輸出:

call ex2->say(): something else 
call ex1->say(): something else 
debug: ex1=0xf1e010; ex2=0xf1e010 

因此,我期望ex2是從ex1不同,因此預期ex2->test = "something else";不改變ex1。我猜這是有意的行爲,但爲什麼? (如果它們沒有什麼不同,爲什麼會甚至是必要的任何分配到的dynamic_cast?(其中一個結果可能繼續使用ex1?))

任何幫助表示讚賞。

+0

你見過http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used? – matsjoyce 2014-12-05 16:21:59

+4

你爲什麼期望它們有所不同?它們是*相同對象*的兩個指針,只是通過*不同的接口*。 – cdhowie 2014-12-05 16:25:02

+0

順便說一下,值得注意的是,即使'ex1'中的原始指針值不等於'ex2'中的原始指針值,它們仍然會指向同一個對象。向下或向上轉換對象指針會導致不同的內存地址,具體取決於編譯器如何爲層次結構中的每個類設置vtables。 (對於多重繼承尤其如此。) – cdhowie 2014-12-05 16:28:50

回答

4

我想這是打算的行爲,但爲什麼?

您正在投射指向不同類型的指針,而不是創建新對象。兩者都指向相同的Example對象;一個將其視爲MyInterface,另一個視爲SubInterface。因此,在通過一個指針修改對象之後,對其進行的更改通過另一個指針可見,因爲它們都指向相同的對象。

如果他們沒有不同,爲什麼甚至需要分配任何東西到dynamic_cast的結果?

它們不一定相同。通過多重繼承,不同的基類子對象可能位於完整對象內的不同位置。在這種情況下,可能需要調整指針值以指向完整的對象。

可以繼續使用ex1

不會,就像你的情況一樣,它具有相同的值,它有錯誤的類型。它被宣佈指向MyInterface,它沒有test成員,所以你不能說ex1->test

1

ex1和ex2指向相同的對象,但具有不同的類型。換句話說,內存是相同的(同一個Example對象),但是如何操作內存是通過兩個不同的接口(MyInterface或SubInterface)完成的。

dynamic_cast是一個運行時間轉換,可用於通過不同的(相關)接口安全地操作數據,而不是另一個變量的類型允許的數據。這有很多用途,雖然你的例子當然不需要它。

1

什麼dynamic_cast不只是額外驗證指向對象的實際類型相匹配您所期望的一個,如果他們不返回nullptr。如果它們匹配,它會返回一個指向同一個對象的指針,就好像你已經做了static_cast(形象地說,除了運行時檢查之外還有一些其他細微差別)。此額外驗證不會創建新對象。 dynamic_cast沒有改變對象 - 你做了。

+1

它實際上可以返回一個不同的指針值,但它指向(因此將比較等於)原始對象。 – cdhowie 2014-12-05 16:32:09

+0

@cdhowie謝謝,澄清說。 – BartoszKP 2014-12-05 16:33:41

+1

謝謝。對於任何對我的意思感到困惑的人,[這裏是一個例子](http://ideone.com/QW7U7p)。請注意,'B'指針與'C'指針的值不同,但它仍然與它相等。 – cdhowie 2014-12-05 16:36:24

1

Dynamic_cast不會更改原始對象,在您的案例'ex1'中。最初分配的內存保持不變。否則,你會有各種泄漏和內存損壞。

你的意圖似乎也是要了解它是否能給你一個不同於輸入指針的指針。

要理解這一點,你必須理由兩個方向 - 向上轉型和向下轉換和繼承的成員變量等

有其他人對這個問題的答案優異。建議搜索相關的。

相關問題