2012-12-09 22 views
10

如果你有以下幾點:dynamic_cast如何工作?

class Animal{}; 

class Bird : public Animal{}; 

class Dog : public Animal{}; 

class Penguin : public Bird{}; 

class Poodle : public Dog{}; 

是否dynamic_cast的只是檢查,如果一個類是派生類中的另一個,或者如果一個類是基類的另一個?所以,如果我有:

Bird* bird; 
Animal* animal; 

bird = dynamic_cast<Animal*>(bird); 
animal = dynamic_cast<Bird*>(animal); 

bird現在將指向一個Animal類,這樣我可以用bird->some_function();,它會調用該函數在Animalanimal現在指向Bird班,所以我可以做animal->some_function();,它會在Bird中撥打some_function();

我一直在試圖弄清dynamic_cast是如何工作的,以及我在網上找到的資源並不是最有用的。如果有人能夠提供有關dynamic_cast功能的其他洞察以及一些有用的實例,我將非常感謝。

+1

您投下了錯誤。 「鳥」和「動物」已經是指針了,但你正在考慮他們的地址。 –

+0

@Olaf。感謝您的編輯。也許你應該刪除你的評論。 –

回答

8

動態演員陣容最重要的是它應該被應用於polymorphic type。如果沒有這種動態投射就像靜態投射一樣。

什麼是多態類型?任何具有至少一個虛擬方法或虛擬析構函數或虛擬基類的類都是多態的。只有這些類型的數據佈局中有virtual method table(VMT)。沒有虛擬任何東西的類沒有VMT。標準並不是說應該如何實現polymorphysm和虛擬方法,同時所有編譯器(AFAIK)都這樣做。

在你的例子中,類不是多態的。在我看來,如果編譯器將動態強制轉換應用於非多態類型時會發生錯誤,那將會更好。不過他們不這樣做。這增加了混亂。

所有類的VMT指針是不同的。這意味着在運行時看着:

Animal* animal; 

有可能知道對象的真實類是什麼。它是一個BirdGod或別的東西。根據VMT的值瞭解真實類型,如果需要,生成的代碼可以進行調整。

下面是一個例子:

class Animal { virtual ~Animal(); int m1; }; 
class Creature { virtual ~Creature(); int m2; }; 

class Bird : public Animal, Creature { }; 

Bird *bird = new Bird(); 
Creature *creature = dynamic_cast<Creature*>(bird); 

注意該生物不是第一基類。這意味着指針將被移動以指向對象的右側部分。儘管如此,下面還是會工作:

Animal *animal = dynamic_cast<Animal*>(creature); // Case2. 

因爲生物的VMT當它是其他類的一部分將是不一樣的,以VMT的對象的時候才使用獨立:

Creature *creature1 = new Creature(); 

這種區別允許適當地實施動態演員。在示例Case2中,指針將被移回。我測試了這個。這工作。

2

這並沒有太大的意義,因爲你把它。

dynamic_cast的意義在於在運行時解決多態性問題。因此,實際有趣的場景會是這樣的

void animalhandler(Animal& animal); 

然而,被稱爲與Animal實例(至少不僅是),但與任子類。您通常甚至不需要知道:您可以調用任何虛擬成員animal,並確保C++調用正確的超載,無論實際屬於哪個派生類*animal

但是有時候你希望做某件事情,這隻能通過一個特定的派生實例來實現。在這種情況下,你使用dynamic_cast,像

void animalhandler(Animal& animal) { 
    if(auto as_bird = dynamic_cast<Bird*>(&animal)) { 
    // bird-specific code 
    } 
} 

其中if只有火災,如果animal事實上是Bird(或派生的Bird),否則dynamic_cast剛剛返回nullptr其中if解釋爲false

現在,你想出了做相反的想法。讓我們看看這將是什麼樣子:

if(auto as_bird = dynamic_cast<Bird*>(&animal)) { 
    if(auto as_animal = dynamic_cast<Animal*>(as_bird)) { 
     // animal-specific code 
    } 
    } 

......等等,這是否意味着什麼是動物特定的?沒有,因爲全部Bird s是Animal s,我們知道在編譯時動態檢查它是沒有意義的。你仍然可以編寫它,但是你可以直接使用as_bird,因爲它可以訪問所有as_animal會員。

3

dynamic_cast運算符檢查指針所指向的對象的類型實際。這是什麼使它不同於編譯時static_cast; dynamic_cast的結果取決於運行時數據。

dynamic_cast<Animal*>(bird) 

在上述情況下,AnimalBird一個超所以dynamic_cast在這裏沒有必要(和編譯器會把它同一個static_cast或不投的話)。

dynamic_cast<Bird*>(animal) 

在這種情況下,當實際執行該語句,運行時系統會檢查實際的類型任何種類的對象animal實際上指向。它可能是BirdBird的子類,在這種情況下結果將是有效的Bird*。如果對象不是Bird,則結果將是NULL

由於您將這些dynamic_cast調用的結果分配回原始指針,您的問題更加複雜。這也許是混淆的一部分,我從上面的討論中忽略了這個方面。

0

我希望這有助於:

#include <iostream> 
#include <algorithm> 
#include <vector> 
#include <utility> 

using namespace std; 

class A{ 
public: 
    A(){} 
    virtual void write() const = 0; 
}; 

class B : public A{ 
public: 
    B(){} 
    void write() const { cout << "I'm B" << endl; } 
    void iam(){ cout << "Yes, I am" << endl; } 
}; 

int main(){ 
    B b; 

    A* a; 
    a = &b; 

    b.write(); 
    b.iam(); 

    a->write(); 
    //a->iam(); A don't have a method iam 


    system("pause"); 
    return 0; 
} 
0

從C++工作草案

動態施放[expr.dynamic。投]

1表達的dynamic_cast的結果<Ť>(v)爲轉換表達式v到類型T.Ť應的指針或引用到一個完整的類型,或「指向cv的結果空隙。」該dynamic_cast運算不應拋棄常量性(5.2.11)。

6否則,v應的指針或一個多態型(10.3)的左值。

8如果C是T類指向的類類型,運行時檢查在邏輯上執行如下:
- 如果在最大派生對象指向(r (引用)到v,v點(引用)到C對象的公共基類子對象,並且如果只有一個類型爲C的對象從v指向(引用)的子對象派生出來, C對象。 - 否則,如果v指向(派生)最派生對象的公共基類子對象,並且最派生對象的類型具有類型C的基類,該類型是明確且公有的,則結果指向(引用)給最派生對象的C子對象。
- 否則,運行時檢查失敗。

你可以從這些條款能得出什麼結論

  • dynamic_cast作品多態類
  • 它着眼於運行在指向的對象(或簡稱)到
  • 它決定基於公開指向對象的基類,是否投出成功或失敗