为什么这个奇怪的重复出现的模板模式示例不能编译?
Why doesn't this curiously recurring template pattern example compile?
我相信这是奇怪的重复模板模式的一个例子。在我看来,这应该可以编译,但事实并非如此。这是 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>
?
协变参数类型在 C++ 中没有,从来没有,而且很可能永远不会工作。您可能认为您的示例 "obviously" 安全。但该功能通常是不安全的,添加对如此小的用例的支持不会发生。
举例说明:
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
作为食物处理,但它 是一个 animal
。这违反了里氏替换原则。
我相信这是奇怪的重复模板模式的一个例子。在我看来,这应该可以编译,但事实并非如此。这是 Xcode 8.3.
中的 Clangtemplate<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>
?
协变参数类型在 C++ 中没有,从来没有,而且很可能永远不会工作。您可能认为您的示例 "obviously" 安全。但该功能通常是不安全的,添加对如此小的用例的支持不会发生。
举例说明:
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
作为食物处理,但它 是一个 animal
。这违反了里氏替换原则。