2013-04-07 60 views
1

我在基類中定義爲純虛函數 虛擬int GetData() const = 0;虛擬函數返回類型

在每個派生類中,我定義一個枚舉並嘗試重寫GetData函數返回 (派生類特定枚舉)值;

例如:

class Derived1 : public Base 
{ 
public : 
enum D1 
{ 
    d1_1 = 0, 
    d1_2 = 60, 
    ... 
    d1_100 
}; 
D1 GetData() const; 
}; 
class Derived2 : public Base 
{ 
public : 
enum D2 
{ 
    d2_1 = 10, 
    d2_2 = 39, 
    ... 
    d2_300 
}; 
D2 GetData() const; 
}; 

地說,我不能老是Ðefine相同範圍從所有類的所有枚舉valuyes這是非常重要的。上述 的代碼生成編譯錯誤:

error C2555: : overriding virtual function return type differs and is not covariant 

任何建議 - 如何解決?

+3

更改返回類型爲'int'無處不在? – 2013-04-07 19:01:45

+0

這不是很好,因爲它對保留和使用枚舉的其他功能很重要 – Yakov 2013-04-07 19:04:50

+0

這個小缺點是它沒有意義,儘管:-( – 2013-04-07 19:05:27

回答

2

在您的特定情況下,它是你的virtual方法返回一個基本類型,它沒有協方差,因爲它不能在C#付諸常見的類型像System.Object的事實。
您需要定義一個類作爲所有返回類型的基類,以便滿足協方差。

維基百科:

Within the type system of a programming language, covariance and contravariance refers to the 
ordering of types from narrower to wider and their interchangeability or equivalence in certain 
situations (such as parameters, generics, and return types). 

covariant: converting from a specialized type (Cats) to a more general type (Animals): 
Every cat is an animal. 

Here是鏈接到文章。

1

只有在指針/引用指向派生類的指針/引用時,才允許更改虛函數的返回類型,因爲可以安全地將其轉換爲另一類。雖然枚舉類型和int兼容,但它們在技術上沒有關係。隨處可以使用int,因爲枚舉名稱只是一種裝飾,根本不會影響任何內容。

+0

-1「更改虛函數的返回類型是不允許的並且沒有意義」是不正確的(C++支持協變原始指針和參考函數的結果) – 2013-04-07 19:09:28

+0

我剛剛意識到這一點,並已經修復,雖然它可能不是提問者正在尋找的東西 – riv 2013-04-07 19:10:38

+0

好的,我正在刪除downvote,但請注意,修訂中的邏輯並不真正起作用。現在的事實是可以的,推理無效(舊C++ 03枚舉隱式轉換爲int,就像派生指針隱式轉換爲基類p ointers)。 – 2013-04-07 19:12:19

1

您的設計需求是固定的,但對於剛剛技術你可以做

class Derived1 
    : public Base 
{ 
public: 
    enum D1 
    { 
     d1_1 = 0, 
     d1_2 = 60, 
     ... 
     d1_100 
    }; 
    D1 GetD1Data() const; 
    int GetData() const override { return GetD1Data(); } 
}; 
+0

此解決方案生成另一個編譯錯誤重載函數僅在返回類型不同... – Yakov 2013-04-07 19:21:42

+1

@Yakov:只是修復你的錯誤。對不起,但沒有訪問你的代碼,我看不出你的代碼到底出了什麼問題。我可以猜測*然而,你無意中給了這兩個函數相同的名字? – 2013-04-07 19:23:27

+0

也許你可以添加一個明確的'int' _enum-base_。 – dyp 2013-04-07 19:31:14

1

根據C++ 11 ISO 10.3/7:

的的返回類型一個覆蓋函數應該是與覆蓋函數的返回類型相同,或者與協變函數的類別一致。如果函數d :: F覆蓋的函數B :: f,其返回類型的功能協變,如果他們滿足下列標準

- 兩者都是類型指針,兩者都是對類的引用左值,或者兩者都是類的引用

- B :: f的返回類型中的類與D :: f的返回類型中的類相同,或者是明確可訪問的直接或返回類型的類的間接基類D :: f

- 指針或引用都具有相同的cv-qualificat並且返回類型D :: f中的類類型具有與返回類型B :: f中的類類型相同的cv限定或更少的cv限定。

協變只允許用於指針,左值/右值引用。我想你不想通過引用或指針返回枚舉。

但是,如果你接受靜態線程本地緩存,您可以使用以下方法:

LIVE DEMO

class EnumA 
{ 
    int value_; 
public: 
    explicit EnumA(int v) 
     : value_{v} 
    {} 
    int value() const 
    { 
     return value_; 
    } 
}; 
struct EnumB: EnumA 
{ 
    enum EnumB_T{one,two}; 
    explicit EnumB(EnumB_T v) 
     : EnumA{v} 
    {} 
    EnumB_T value() const 
    { 
     return EnumB_T(EnumA::value()); 
    } 
}; 

struct A 
{ 
    virtual const EnumA &func() const 
    { 
     static thread_local EnumA result{0}; 
     return result = EnumA{1}; 
    } 
}; 

struct B: A 
{ 
    virtual const EnumB &func() const override 
    { 
     static thread_local EnumB result{EnumB::one}; 
     return result = EnumB{EnumB::two}; 
    } 
};