2012-04-04 103 views
0

此問題是關於用不同返回類型覆蓋派生類中的虛擬方法的問題。 對於下面的代碼:重寫虛擬方法時無法返回派生類指針

class father { 
public: 
    virtual father* ref() { return this; } 
}; 

class child : public father { 
    virtual child* ref() { return this; } 
}; 

當我嘗試直接獲取一個指針,G ++(F15,G ++ 4.5)報告 「無效的轉換,從父親的孩子」

child m_child; 
father* pf = &m_child; 
child* pc = pf->ref(); 

我明白使用子類中的ref()方法,這可能只是編譯時類型不匹配。

但是,有沒有辦法做到這一點,而不明確使用類型轉換?

額外描述: 我明白編譯器報告此錯誤的原因。我需要的是可以訪問派生對象中的數據而不顯式轉換指針的開箱即用的東西。

父類用於將不同的派生子對象放入列表或向量中,所以當從列表或向量中獲取某個項時,無法確定它屬於哪個子類。

我有內部方法來記錄和檢查子類的類型。但我不想顯式地轉換指針。

例如,我願做這樣的事情:

// assuming pf is pointer pointed to an item fetch from a vector 
switch(fp->get_type()) { 
case child_type1: fp->ref()->list1.push(data); break; 
case child_type2: fp->ref()->list2.push(data); break; 
case child_type3: fp->ref()->list3.push(data); break; 
} 

現在,我需要顯式聲明一個新的變量或顯式轉換FP在每種情況下,每個我需要時間正確的類型和訪問派生類中的數據,這是枯燥乏味的。

我期望的是:可能是一些boost庫可以以另一種我還不知道的方式做類似的事情,或者可能是C++ 11標準允許它,但需要設置一個特殊的編譯參數?

+0

我想我很理解爲什麼編譯器報告類型不匹配。我需要的不是對這裏發生的事情的解釋。我需要一些開箱即用的東西。爲了進一步解釋它,請參閱添加的額外說明。 – 2012-04-04 13:41:38

回答

2

簡單的答案是「否」。

你已經失去的額外信息(child*而不是father*)約ref當你扔掉m_child S型的信息,將它存儲爲指針基地(pf)。

一個原因就是它永遠無鑄有可能是這樣的例子:

class father { 
public: 
    virtual father* ref() { return this; } 
}; 

class childA : public father { 
    virtual childA* ref() { return this; } 
}; 

class childB : public father { 
    virtual childB* ref() { return this; } 
}; 

void should_never_compile(int i) 
{ 
    childA a; 
    childB b; 
    father pf; 
    if(i) { pf=&a; } 
    else { pf=&b; } 

    // This is evil and will not compile 
    childA * pa = pf->ref(); 

    //But this is OK: 
    childA * pa = dynamic_cast<childA*>(pf->ref()); 
} 

如果你真的想這是可行的,而不動態轉換,你可以只隱藏動態轉換(但它讓我害怕一點點)

class father { 
public: 
    virtual father* ref() { return this; } 
    template<typename T> T* as() { return dynamic_cast<T*>(ref()); } 
}; 

child m_child; 
father* pf = &m_child; 
child* pc = pf->as<child>(); 
+0

謝謝,你給我提供了一些看起來更好的東西! – 2012-04-04 13:54:35

1

您的功能可以滿足您的期望以及您的要求。該行

child* pc = pf->ref(); 

是問題所在。你可以在父指針上調用函數「ref()」,該指針返回(按類型)父*。您將這個 - 無需轉換 - 分配給一個孩子*。該函數的實現返回一個孩子*,但從你稱之爲信息未知的地方,因爲你只知道它是一個父親*。因此,返回類型是一個父類*(如類父所指出的那樣),並且您將其分配而不轉換爲子類*。您可以做:

child *pc = m_child.ref(); 
father *pf = m_child.ref(); 
father *pf2 = pf->ref(); 
+0

很好解釋@dascandy – Ricketyship 2012-04-04 13:28:00

1

的問題是,在呼叫pf->ref()ref類型是:father* (father::*)()

也就是說,ref被解析爲靜態地是具有給定簽名的virtual方法。這個簽名表示它返回一個father*

這樣:

int main() { 
    father f; 
    father* pf = &f; 

    child c; 
    child* pc = &c; 

    child* xf = pf->ref(); // compile-time failure 
    child* xc = pc->ref(); // okay 
} 

的問題是,在一般情況下,從father*開始,你可以不知道你是否會得到一個child*,這取決於動態類型的實例。所以編譯器假設最壞的情況:它至少是father

相關問題