2017-09-04 54 views
1

我相信這是一個奇怪的循環模板模式的例子。在我看來,這應該編譯,但事實並非如此。這是在Xcode 8.3中的Clang。爲什麼這個好奇的循環模板模式示例不能編譯?

template<class T> 
class Fungeable 
{ 
public: 
    virtual ~Fungeable() {} 
    virtual bool funge(const Fungeable<T>& inFungeable) const = 0; 
}; 

class Blarg : public Fungeable<Blarg> 
{ 
public: 
    virtual bool funge(const Blarg& inFungeable) const override { return true; } 
}; 

int main(int argc, const char * argv[]) { 
    Blarg b; 
    Blarg x; 
    return static_cast<int>(b.funge(x)); 
} 

看起來這應該工作,因爲Blarg 是一個 Fungeable。但我得到的錯誤'funge' marked 'override' but does not override any member functions

如果我改變的Blarg::funge()簽名採取Fungeable<Blarg>這樣的:

class Blarg : public Fungeable<Blarg> 
{ 
public: 
    virtual bool funge(const Fungeable<Blarg>& inFungeable) const override { return true; } 
}; 

然後再編譯。

由於Blarg的定義和定義Fungeable<Blarg>不應該是第一個版本?

+1

「因爲Blarg的定義是Fungeable 」每個Blarg'都是一個Fungeable '但不是每個Fungeable 都是一個Blarg。 – tkausl

回答

3

Co-variant參數類型不會,從來沒有,並且很可能永遠不會在C++中工作。你可能認爲你的例子「顯然」是安全的。但是這個功能通常不安全,並且不會增加對這樣一個小用例的支持。

舉例說明:

struct food {}; 
struct grass : food {}; 

struct animal { 
    virtual void eat(food&) = 0; 
}; 

void feed(animal& a) { 
    a.eat(grass{}); 
} 

到目前爲止好。現在,讓我們添加更多的層次,假設我們有合作變的參數類型:

struct meat : food {}; 

struct lion : animal { 
    void eat(meat&) {/*...*} 
}; 

當我通過一個lion對象feed會發生什麼?它不能處理grass作爲食物,但它is-aanimal。這打破了Liskov替代原則。

+1

在你的第一句話中,你的意思是'參數'而不是'返回'嗎? –

+0

@MatthewJamesBriggs - 哎呦。是的,我願意。支持Co-variant返回類型,這是我的主要錯誤。 – StoryTeller