2015-02-24 78 views
4

我有這相當於代碼這一個:C++多重繼承協變返回類型錯誤

class X {}; 
class Y {}; 

template< typename T> 
    class C { 
    public: 
     virtual T * foo() = 0; 
    }; 

class A : public C< X> { 
public: 
    X * foo() {}; 
}; 

class B : public A {}; 

class D : public B, public C< Y> { 
public: 
    Y * foo() {}; //this is the only one method I need here. Not A::foo! 
}; 

我得到這個錯誤:

error: invalid covariant return type for 'virtual Y* D::foo()' 
Y * foo() {}; 
    ^

和:

error: overriding 'virtual X* A::foo()' 
X * foo() {}; 
    ^

http://ideone.com/PAgTdX

我相信我可以在B類D以防止A :: foo從繼承,但我不知道是什麼。也許有一些功能可以重命名C++中的衝突名稱?

PS>我不能使用C++ 11,只能使用舊的C++ 98。

+0

如果從'C '繼承的'foo'是你想要的唯一一個,那你爲什麼要從'B'繼承?這似乎是一個潛在設計問題的症狀。 – 2015-02-24 13:45:37

+0

B和D是我在代碼中分別使用的兩個類。 – 2015-02-24 14:17:02

+0

我已經問過一個類似於這個問題:http://stackoverflow.com/questions/28240936/whats-the-best-way-to-implement-ast-using-visitor-pattern-with-return-value,the第二個答案可能會提供你想要的,但它確實需要C++ 11。 – swang 2015-02-24 14:29:29

回答

1

TL; DRD

foo重寫。 foo方法由於不相關的XY返回類型而不能協變。也不能由於不同的返回類型而簽名相同而不能重載。


說明

讓我們清理代碼用同樣的問題較小的片段:

class X {}; 
class Y {}; 

template<typename T> 
class C { 
public: 
    virtual T * foo() = 0; 
}; 

class A : public C<X> { 
public: 
    // Your code: 
    // X * foo() {}; <---- This method is irrelevant to the problem 

    // virtual X * foo() {}; 
    // ^^^^^^^^^^^^^^^^^^^^^ 
    // This method declared via inheritance and template 
    // and implicitly exists in this class, (look at keyword `virtual`) 
}; 

class D : public A, public C<Y> { 
public: 
    /*virtual*/ Y * foo() {}; // `virtual` comes from C<X> 
}; 

嗯,類D繼承AC<Y> 2種foo方法。這兩種導入的方法可以共存,因爲它們來自不同的父母,可以通過合格的呼叫來呼叫,例如D d; d.A::foo();

 

但在這種情況下,問題就來了進入畫面,當您嘗試D類重寫foo

/*virtual*/ Y * foo() {}; 

D類中,有一個與遺傳簽名X * foo()的方法從A開始,並且您正在重寫方法Y * foo()。這些不能協變,because Y is not derived from X。另一方面,foo不能超載另一個,Because return type is not part of function signature

 

這是很好的閱讀鐺的錯誤消息:

error: return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('Y *' is not derived from 'X *')

virtual Y * foo() {}; 

解決方案

最好的解決方法是簡化您的設計,擺脫這些複雜的繼承,模板和相同的名稱方法!

+0

感謝您提供清晰和完整的答案。即使沒有_D_類的繼承,您正在給出的代碼(不在_A_類中實現_foo_方法)也不會編譯。如果我理解你是對的。 – 2015-02-25 13:32:52

-1

你可以使用private inheritance爲A.

class B : private A {}; 

一般情況下,返回類型不能超載的唯一區別。

+1

你測試了嗎?它不適合我。 – deepmax 2015-02-24 13:32:19

+0

對我來說也是。 http://ideone.com/uv7MKB – 2015-02-24 13:35:43

0

你說你不需要foo方法,你在C<X>聲明和A實現,但因爲你的D類也是安AC<X>,客戶端可能會依賴於這種方法可用,並返回一個X。 C++不支持刪除繼承的方法AFAIK,並有充分的理由,因爲這會違反Liskov替換原則。

如果你沒有刪除或隱藏C<X>::foo這裏,那麼不能使用的D一個實例,其中的AB,或C<X>實例的預期。所以恐怕這裏沒有解決這個問題的好辦法。如果您只是試圖重複使用D中的AB實現,那麼在這種情況下您應該考慮組合而不是繼承。