【问题标题】:How should I implement a pure virtual method with derived type as parameter?我应该如何实现一个以派生类型为参数的纯虚方法?
【发布时间】:2015-12-24 07:08:24
【问题描述】:

我正在用 C++ 编写程序,我来自 Java,但遇到了一些麻烦。 我想要一个基本抽象类(一个java接口),它定义了派生类必须实现的一些方法。这个方法可以将派生类型作为参数,但是在这里我发现了一个问题。如果我使用基类将它们定义为基类中的参数,编译器不会将派生类型的重新定义视为覆盖,并且派生类仍然是纯虚拟的。 解决这种情况的正确方法是什么? 谢谢!

【问题讨论】:

  • 这也不应该在 Java 中工作。逆变要求在基类签名中具有派生类型,在派生类签名中具有基类型。

标签: c++ oop inheritance


【解决方案1】:

你应该在这里做的是在派生类中创建一个以基类为参数的函数。您可以使用dynamic_cast 来确保运行时类型确实是派生类(否则抛出异常)。正如克里斯在他的评论中提到的那样,逆变是“难的”。

class Base
{
    public:
    virtual void fn(const Base &base)=0;
}
class Derived:public Base
{
     void fn(const Base &base)
     {
         const Derived *derived=dynamic_cast<const Derived *>(&base);
         if(derived!=nullptr)
         {//code for derived..
         }

     }
}

如果你真的必须拥有你想要的东西,你应该去CRTP。我怀疑你真的不需要。如果您真的需要它,Adrian 的答案就是您想要的。

请记住,如果您选择 CRTP,您将失去继承的一些好处。例如,您无法创建基类指针列表 (vector &lt;Base *&gt;)。每当您使用基类 (Base&lt;Derived&gt;) 时,您都需要选择派生类,这可能会破坏目的。

【讨论】:

  • 我会在代码审查中标记它这违反了 Liskov 原则,因为我不能在任何需要 Base 对象的地方使用 Derived 对象。
【解决方案2】:

我想你想写这样的东西:

template<class T>
class Interface {
  virtual void Method(T i) = 0;
};

class Implement : public Interface<Implement> {
  virtual void Method(Implement i) override {

  }
};

这叫CRTP

【讨论】:

    【解决方案3】:

    您尝试做的事情在 Java 中也行不通。在 Java 中,返回类型可以是协变的,但方法的参数不能。如果您考虑 Liskov 原则,这实际上是有道理的:如果您缩小派生类的合同,您将无法用派生对象替换基对象。

    解决方案可能需要处于设计级别。只是猜测,但这种问题与您希望在类和参数类型上调度的情况有关。如果是这样的话,看看Visitor pattern.

    【讨论】:

      猜你喜欢
      • 2018-10-14
      • 2014-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-30
      • 2019-12-11
      • 2018-02-27
      • 1970-01-01
      相关资源
      最近更新 更多