2012-06-20 34 views
5

我試圖在其繼承樹中的一個類的構造函數中發現對象的最派生類。我已經花了好幾個小時來解決這個問題,並且對於我該怎麼做,或者爲什麼沒有意義,我感到不知所措。它似乎很有道理,但它拒絕工作。我發現了很多關於RTTI的網頁,並且基本上與他們無關。在我的測試用例及其輸出結束後,我會繼續進行解釋。「this」指針RTTI啓用了嗎?

源:

#include <iostream> 
#include <typeinfo> 
#include <string> 

class A 
{ 
public: 
    A(std::string foo); 

    virtual void bar(A* a) = 0; 
}; 

class B : public A 
{ 
public: 
    B(); 

    virtual void bar(A* a); 
}; 

A::A(std::string foo) 
{ 
    std::cout << "type as passed to A constructor: " << foo << " (" << this << ")" << std::endl; 
    std::cout << "type as determined in A constructor: " << typeid(*this).name() << " (" << this << ")" << std::endl; 
} 

B::B() : A(typeid(*this).name()) 
{ 
    A* a = (A*)this; 
    std::cout << "type as determined in B constructor: " << typeid(*a).name() << " (" << this << ")" << std::endl; 
    this->bar(this); 
} 

void B::bar(A* a) 
{ 
    std::cout << "type as determined in bar: " << typeid(*a).name() << " (" << a << ")" << std::endl; 
} 

int main() 
{ 
    B b; 
    b.bar(&b); 

    return 0; 
} 

輸出(對於g ++):

type as passed to A constructor: 1B (0x7fff5fbff910) 
type as determined in A constructor: 1A (0x7fff5fbff910) 
type as determined in B constructor: 1B (0x7fff5fbff910) 
type as determined in bar: 1B (0x7fff5fbff910) 
type as determined in bar: 1B (0x7fff5fbff910) 

我想要得到的輸出的第二行說 「1B」,而不是 「1A」 。 由於某些原因,我無法想象RTTI是否從「this」中刪除?這不會打破虛擬功能的想法嗎?(我已經用虛函數實現了這個功能,直到我發現我重新實現了RTTI的一部分,我之前並不知道)。輸出結果顯示,如果我避免使用「this」,我可以做到這一點,但需要要做到這一點看起來像設計破損。

+2

你爲什麼要檢測類型?這是不好的。這聽起來像是一種嘗試(有缺陷)的解決方案,那是什麼? –

+0

Alf,我將std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std :: std ::某個類的每個實例都有其自己的這種映射,以便允許將新對象輕鬆添加到這些核心對象中,並稍後通過類型進行檢索。 (在我知道RTTI之前,我使用const ints和虛擬方法的網絡進行此操作,出於同樣的原因出現同樣的故障。) – Grault

回答

4

你不能這樣做,因爲你誤解了所涉及的動態。

的規則是:任何類口岸到它的構造/析構函數,該類

在構造函數中的this /析構函數。

而且,這是什麼原因virtual函數調用構造函數中不規矩,你通常會想到virtual功能使用動態調度時工作。

你應該檢測後的構造已經called.You可以在任何的成員函數這樣做,除了構造函數和析構函數。

+0

好吧,但爲什麼這樣更好?對我來說,這似乎並不直觀。它會破壞一些其他的OO功能嗎? – Grault

0

考慮您的繼承關係,你應該已經知道的A構造函數會執行,然後再B的一個意願。在A的構造函數中,該對象尚未構造爲B。因此,構造函數中對象的動態類型始終是類本身的類型,決不是派生類的類型。析構函數也是如此。

換句話說,你想要做的事情不能做在建設時間

+0

「A的構造函數將首先執行,然後B的構造函數將執行」。這是我認爲的,直到我能夠將「this」作爲B傳遞給A構造函數(這在測試用例中隱含地演示)。我現在將flow理解爲最先執行的構造函數,每個構造函數在執行其他任何操作之前調用它的父級構造函數。因此,如你所說,身體從根部運行。 – Grault

3

您正在看到預期的行爲。在構造函數的主體中,正在構造的對象的類型與其構造函數正在執行的類的類型相同,而不是構造的最派生類的類。

在成員初始值設定項表達式中使用時,異常確實存在於表達式typeid(*this)中。這在C++ 03中曾經是未定義的行爲,但是這已在C++ 11中進行了更改,以便您獲取構造函數類的類型而不是尚未構造的實際對象的類型。