【问题标题】:Overriding an operator to use the derived class in C++覆盖运算符以使用 C++ 中的派生类
【发布时间】:2017-03-13 20:50:39
【问题描述】:

我试图覆盖子类中的虚拟比较运算符,但我收到一个编译器错误,指出派生类没有实现基类的虚拟运算符。

我感觉这与我的派生运算符不使用基类的参数类型有关。

简化版如下:

struct Base {
  virtual bool operator ==(const Base) const;
};

struct Derived : Base {
  bool operator ==(const Derived) const {
    // implementation goes here
  }
};

我有办法做到这一点,还是我必须在 Derived 实现中进行类型检查以查看它是否是正确的类型?

【问题讨论】:

  • 虚拟比较为您提供运行时类型检查,您想要吗?
  • @Cheersandhth.-Alf 我想我会,我会有一个充满不同派生类的向量,所以在不知道哪个是哪个的情况下,我想让操作员处理两个类具有相同的派生类型
  • 投票结束,因为缺乏可重复的例子
  • @Cheersandhth.-Alf 我不确定我给出的例子是不够的。它准确地说明了我想要做什么
  • 如果您将引用作为参数传递?

标签: c++ inheritance operator-overloading overriding subtyping


【解决方案1】:

我感觉这与我的派生运算符有关 不使用基类的参数类型。

确实如此。基类必须采用 const reference(这样它就可以具有动态类型 Derived,然后您将覆盖声明为:

bool operator ==(const Base& rhs) const {
    const auto pRhs = dynamic_cast<const Derived*>(&rhs);
    if (pRhs == nullptr)
    {
        return false;  // Not a derived.  Cannot be equal.
    }
    // Derived/Derived implementation goes here
}

但请注意:像这样的虚拟比较运算符很容易出错。你需要一个很好的激励例子来做到这一点。特别是,如果你写:

Derived d;
Base b;
if (d == b)  // All is well - derived override called, and returns false.

if (b == d) // Uh-oh!  This will call the *base* version.  Is that what you want?

还有:

Derived d;
DerivedDerived dd;

if (d == dd) // Did you want to use the DerivedDerived comparison?

【讨论】:

  • 那么,如果右手边比Derived 更派生怎么办?换句话说,此代码仅在比较表达式的左侧分派。
  • @Cheersandhth.-Alf :坏东西 - 这是一个很好的例子!
  • 无论如何,@Electric Coffee,每次你声明一个覆盖其父类中的虚函数的成员函数时,使用'override'!
  • @DonghuiZhang 这个 override 关键字是在 C++11 中引入的,我是在 C++98 中工作的,请注意你的选择
  • @ElectricCoffee:在 C++98 中模拟 override 的最佳方法是将 (void) sizeof( Base::foo( args ) ) 放在覆盖的主体中。它检查基类版本是否存在,但不检查虚拟性。
【解决方案2】:

您必须在 Derived 实现中键入检查参数是否具有预期的类型。

对于运算符,您可能更喜欢定义一个虚拟标准方法,然后通过调用此方法来实现您的运算符。这样可以避免对操作员产生意外或太大的签名。

struct Base {
  virtual int compare(const Base& source) const { return 0; }

  bool operator ==(const Base& source) const
    { return compare(source) == 0; }
};

struct Derived : Base {
  int compare(const Base& asource) const override
    { const Derived* source = dynamic_cast<const Derived*>(&asource);
      int result = -2;
      if (source) { ... result = ...; }
      return result;
    }

  // redefinition to force the expected/right signature at this level
  bool operator==(const Derived& source) const
    { return compare(source) == 0; }
};

【讨论】:

  • 为什么只调度左手参数的类型?
  • @Cheersandhth.-Alf 我同意:如果你有 2 个派生类,并且如果你想让它们具有可比性,你需要找到一种一致的方法来消除这两种类型的歧义——多方法更通用。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多