代码之家  ›  专栏  ›  技术社区  ›  Matthew James Briggs

为什么这个奇怪的循环模板模式示例不编译?

  •  1
  • Matthew James Briggs  · 技术社区  · 7 年前

    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 ) );
    }
    

    看起来这应该行得通,因为布拉格 是一个 '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 根据定义,是 可替换<布拉格> ?

    1 回复  |  直到 7 年前
        1
  •  3
  •   StoryTeller - Unslander Monica    7 年前

    协变参数类型在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-a animal . 这打破了Liskov替换原则。