【问题标题】:operator== marked 'override', but does not overrideoperator== 标记为“覆盖”,但不覆盖
【发布时间】:2021-07-02 12:39:53
【问题描述】:

我在覆盖基类 operator== 时遇到问题。这是代码。

#include <iostream>
#include <vector>

using namespace std;

template <typename T>
class IClient {
  virtual const std::vector<T>& getID() = 0;
  virtual bool isEqual(const std::vector<T>& anotherID) = 0;
  virtual bool operator==(const IClient& anotherClient) = 0;
};

class SeviceClient : public IClient<int8_t> {
  const std::vector<int8_t> ID;

 public:
  SeviceClient(const std::vector<int8_t>& ID) : ID(std::move(ID)) {}
  SeviceClient(const std::vector<int8_t>&& ID) : ID(std::move(ID)) {}

  const std::vector<int8_t>& getID() override {
      return ID;
  }
  bool isEqual(const std::vector<int8_t>& anotherID) override {
      return true;
  }
  bool operator==(const SeviceClient& anotherClient) override {
      return true;
  }
};

它抱怨

 error: 'bool SeviceClient::operator==(const SeviceClient&)' marked 'override', but does not override

当我将函数转换为时,编译器看起来很高兴

bool operator==(const IClient<int8_t>& anotherClient) override {}

这是问题的解决方案还是我在这里遗漏了什么?

谢谢

【问题讨论】:

  • 试试bool operator==(const IClient&amp; anotherClient) override
  • 嗨@MarekR 为什么你认为这是一个糟糕的设计? 1.我想拥有纯虚函数的接口类,以便将来模拟。 2. 其次,我有两个客户SeviceClient : public IClient&lt;int8_t&gt;class SubsciberClient : public IClient&lt;uint8_t&gt;。我也可以编写单个模板派生类,而不是像这样template&lt;typename T&gt; Clinet : public IClient&lt;T&gt; 的两个类,但是选择编写两个不同的派生类。对设计有什么建议吗?
  • @BhanuKiran 相等运算符通常是为具有结构特征的类定义的(没有多态性,没有回调,可以复制的东西)。我不知道您的实际问题的性质是什么,所以我只是猜测,因为这对我来说看起来不正确。

标签: c++ operator-overloading c++14


【解决方案1】:

ServiceClient 和 IClient 是不同的类型。 所以, bool SeviceClient::operator==(const SeviceClient&) 没有基础声明。

【讨论】:

    【解决方案2】:

    您必须了解 C++ 有可能重载函数。 因此,要识别假设被调用的函数,不仅函数名必须匹配,而且参数类型也必须匹配。当然有隐式转换可以调整参数以匹配函数参数类型,但请注意,如果有多个同名函数,则隐式转换会导致歧义。

    如果你使用多态,那么你必须记住子类应该是可用的,因为它只是父类。持有基类指针的人应该不会注意到它实际上是一个子类。

    所以当你重写虚函数时,参数的类型必须非常准确,所以一切都是明确的。

    我怀疑您需要静态多态性和 CRTP 而不是动态多态性。所以是这样的:

    template <typename Child, typename T>
    class IClient {
      const std::vector<T>& getID() {
          return asChild()->getID();
      }
    
      bool isEqual(const std::vector<T>& anotherID) {
          return asChild()->isEqual(anotherID);
      }
    
      bool operator==(const Child& anotherClient) {
          return asChild()->isEqual(anotherClient);
      }
    
    private:
      Child* asChild() {
          return static_cast<Child*>(this);
      }
      const Child* asChild() const {
          return static_cast<const Child*>(this);
      }
    
    };
    
    class SeviceClient : public IClient<SeviceClient, int8_t> {
      const std::vector<int8_t> ID;
    
    public:
      SeviceClient(const std::vector<int8_t>& ID) : ID(std::move(ID)) {}
      SeviceClient(const std::vector<int8_t>&& ID) : ID(std::move(ID)) {}
    
      const std::vector<int8_t>& getID() {
          return ID;
      }
      bool isEqual(const std::vector<int8_t>& anotherID) {
          return true;
      }
      bool operator==(const SeviceClient& anotherClient) {
          return true;
      }
    };
    

    【讨论】:

    • 感谢您的代码。经过一些思考过程和另一个堆栈溢出贡献者的解释。已决定删除运算符重载。感谢您的意见。
    【解决方案3】:

    这个问题有两个方面。一、这种设计违反了哪些C++规则?第二,为什么C++会有这样的规则?

    第一个很简单。您可以使用具有完全相同参数列表的函数覆盖函数。由于(const IClient&amp; anotherClient)(const SeviceClient&amp; anotherClient) 不完全相同,因此不会发生覆盖。结案。

    第二个涉及更多。为了理解它,让我们使用更熟悉的类层次结构。有class Animal,有class Dog : public Animal,还有class Cat : public Animal

    bool Animal::operator==(const Animal&amp;) 告诉我们什么?它告诉我们,我们可以将一种动物与另一种动物进行比较。特别是,我们可以比较狗和狗,猫和猫,狗和猫,老鼠和蝙蝠,鱼和moskito,土豚和霸王龙。这是class Animal 让你成为我们的承诺。如果我们有两个Animal 对象,我们可以比较它们。

    现在,覆盖此运算符的函数应该履行承诺。 bool Dog::operator==(const Dog&amp;) 会这样做吗?不,它实现了一个更窄的承诺:这个Animal(恰好是Dog)可以与Dog 进行比较。履行这个狭隘的承诺是否合法?绝对地。假装这个功能也实现了广泛的承诺,即能够比较任何两种动物,这是否合法?绝对不。所以我们可以声明这个函数,但不能声称它覆盖了Animal相等运算符。

    如果有一条规则允许我们声明,会发生什么?

    Dog d;
    Cat c;
    Animal& da = d;
    Animal& ca = c;
    std::cout << (da == ca);
    

    这个程序片段必须编译,因为每一行都是有效的(根据我们的幻想规则),但是它应该做什么?没有将狗与猫进行比较的代码!

    有些语言会说“好吧,没什么大不了的,我们只会抛出一个运行时错误”。 C++ 不这样做。如果您希望上面的代码引发运行时错误,您应该自己编写引发运行时错误的代码。这意味着用bool Dog::operator==(const Animal&amp;)bool Cat::operator==(const Animal&amp;) 覆盖bool Animal::operator==(const Animal&amp;),并检查那里的错误情况。

    这可能不是一个好主意。平等通常对类层次结构毫无意义。完全省略比较,或者使其成为非虚拟的并仅在子类中定义通常是一个更好的主意。

    【讨论】:

    • 越想越有意义。我决定 tp 删除运算符重载。谢谢你的解释。
    猜你喜欢
    • 2019-08-29
    • 2023-01-27
    • 2018-05-20
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多