2011-09-13 38 views
6

因此,在搜索了很多關於我的問題的答案後,我終於放棄了我的Google技能。重新定義派生類中的typedef?

我有一個基類基地,和派生類派生。我想覆蓋基類類中的類型,其中派生類中的一個。這裏有一個例子:

class Apple { 
public: 
    Apple() { } 

    // ... 

}; 

class Orange { 
public: 
    Orange() { } 

    // ... 

}; 

class Base { 
public: 
    typedef Apple fruit; 

    // ... 

    virtual fruit func() { return Apple(); } 
}; 

class Derived : public Base { 
public: 
    typedef Orange fruit; 

    // ... 

    fruit func() override { return Orange(); } // <-- Error C2555! 
}; 

此代碼不能正常工作,並給出了一個

C2555 error ('Derived::func': overriding virtual function return type differs and is not covariant from 'Base::func'). 

上面是解決我嘗試之一。我也嘗試在基地中創建虛擬嵌套類,並在衍生重新定義,並且也沒有編譯(這也非常混亂)。

我也不能導出蘋果和桔子從同一基類的指針/參考返回到它們的父類中基地派生。我需要物理返回對象的一個​​實例。

  1. 有沒有什麼辦法可以聲明抽象typedefs?
  2. 如果沒有,是否有任何其他解決方案可以實現我想要做的 ?

回答

6

首先,看這個語法:

fruit func() override { return Orange(); } 

什麼是override?在C++ 03中,沒有這樣的關鍵字。它只在C++ 11中。因此,請確保您使用的是知道此關鍵字的編譯器。

二,在派生類中,fruit確實是Orange。重新定義typedef不是問題。問題是,OrangeApple不是協變類型。從另一個派生將使他們協調。在你的情況下,你必須從Apple派生Orange才能使其工作。

注意您對變化fruit要麼fruit*fruit&返回類型。

class Orange : public Apple {}; //correct - your code will work 

class Apple : public Orange {}; //incorrect - your code will not work 

的想法是,在基類,返回類型應該是指針/鹼型(這是Apple)的參考,並在派生類,返回類型可以是指針/參考類型Apple或任何派生它的類。

順便說一句,這是否有意義?從Apple衍生Orange

以下班級設計如何?

class Fruit {}; 
class Apple : public Fruit {}; 
class Orange : public Fruit {}; 

class Base 
{ 
    virtual Fruit* f(); 
}; 

class Derived : public Base 
{ 
    virtual Fruit* f(); 
}; 

不需要使用typedef

+0

「override」關鍵字通過讓編譯器檢查函數是否實際覆蓋任何基本方法來幫助消除人爲錯誤(如錯別字)。至於這個問題,我知道這一點。有沒有什麼辦法可以使它們協變而不使用指針或引用? – Zeenobit

+0

所以我想沒有解決方案來完成這項工作。謝謝,人們。我會嘗試使用不同的層次結構。 – Zeenobit

0

你不能這樣做,如果你有一個值對象,你必須知道它是哪個類型。 (這是像C++這樣的靜態類型語言和Ruby和Python之類的動態類型語言之間的主要區別之一。)

有很多方法可以解決這個問題。首先,我們假設AppleOragne有一個共同的基類,稱爲Fruit。一種解決方案是使用new動態分配對象並返回一個Fruit指針。

另一種解決方案,而不是返回一個值,你的函數可以採取的指針或引用的水果,它則可以填寫。

另一種解決方案是有某種容器對象在內部將舉行蘋果或橙色。這樣你可以返回它。

1

這並沒有太大的意義開始。一個Derived應該能夠在任何地方使用一個Base的預期,所以你應該能夠做到

Base *foo = new Base(); 
Apple x = foo->func(); // this is fine 

Base *bar = new Derived(); 
Apple y = foo->func(); // oops... 

我認爲你需要尋找到一個不同的設計。目前還不清楚你的目標是什麼,但我猜你可能想要Base成爲Fruit作爲模板參數的類模板,或者你可能需要完全擺脫繼承。

0

報告的錯誤告訴你所有你需要的。這意味着在Derived方法中返回的類型需要從基方法返回的類型派生。

這是如此,如果基本方法被虛擬調用,返回的對象可以被看作是由base方法返回的。

實際上,您需要返回一個指針或引用來執行此操作。

你需要做的是定義一個新的Fruit基類,並且有AppleOrange派生自它。

然後有func()返回Fruit*

這會讓你面對在某個時刻確定Fruit*delete'd的問題。

有了更多的上下文,我懷疑(可能很薄)的模板是你所追求的解決方案,而不是繼承。