c++ - "Polymorphic"非成员函数/运算符,我需要额外的重载吗?

标签 c++ c++11 polymorphism operator-overloading

我想覆盖父类的重载运算符,但我想避免样板代码重写继承类的所有非成员运算符。有可能吗?

在下面的示例中,我重载了 virtual Foo & Foo::operator+=(Foo const &) 并基于一个自由函数 Foo & operator+(Foo, Foo const &)出来了。在 Bar 中,我覆盖了 Bar & Bar::operator+=(Foo const &) override。我想要的是当我声明 Bar + Foo 并且我期望 Foo 作为结果时调用覆盖函数的自由函数。我知道再次重载 Bar operator+(Bar, Foo const &) 可以解决该特定情况,但我想尽可能避免明确这样做(考虑所有其他运营商)。然后还有 Foo + Bar 我想返回 Bar

#include <iostream>

class Foo {
public:
  Foo(unsigned int bottles=11) : bottles(bottles) {} // This is odd on purpose

  virtual void display(std::ostream & out) const {
    out << bottles << " bottles";
  }

  virtual Foo & operator+=(Foo const &);

protected:
  unsigned int bottles;
};

std::ostream & operator<<(std::ostream & out, Foo const & f) {
  f.display(out);
  return out;
}

Foo & Foo::operator+=(Foo const &f) {
  bottles += f.bottles;
  return *this;
}

Foo const operator+(Foo f, Foo const & g) {
  return f += g;
}

class Bar : public Foo {
public:
  Bar(unsigned int bottles=0) : Foo(bottles) { enforce(); }
  Bar(Foo const & f) : Foo(f) { enforce(); }

  void display(std::ostream & out) const override {
    out << bottles << " manageable bottles";
  }

  Bar & operator+=(Foo const &) override;

private:
  void enforce() { bottles /= 2; bottles *=2; }
};

Bar & Bar::operator+=(Foo const &f) {
  Foo::operator+=(f);
  enforce();
  return *this;
}



int main () {
  std::cout << "----- Foo + Foo -----" << std::endl;
  Foo bar;
  Foo becue(2);
  std::cout << bar << " + " << becue << " -> (+) "
    << bar + becue << std::endl;

  std::cout << "----- Bar + Bar -----" << std::endl;
  Bar crazy(bar);
  Bar horse(5);
  std::cout << crazy << " + " << horse << " -> (+) "
    <<  crazy + horse << std::endl;

  std::cout << "----- Bar + Foo -----" << std::endl;
  std::cout << crazy << " + " << bar << " -> (+) "
    <<  crazy + bar << std::endl;

  std::cout << "----- Foo + Bar -----" << std::endl;
  std::cout << bar << " + " << horse << " -> (+) "
    <<  bar + horse << std::endl;

  return 0;
}

每次涉及可管理的瓶子时,我都希望得到可管理的瓶子。

最佳答案

问题源于调用时发生的对象切片

Foo const operator+(Foo f, Foo const & g) {
  return f += g;
}

这里,f 是按值传递的,这意味着 Foo 的子类型的任何附加信息都将被丢弃。因此编译器只能看到一个 Foo 并且无法调用多态运算符。

为了防止切片,您必须传递指针或引用,但这意味着您需要一个 l-value 作为第一个操作数,并且您不能使用 const 因为你在上面调用 operator+=

所以你可以

Foo const operator+(Foo& f, Foo const & g) {
  return f += g;
}

它适用于您的特定情况,例如:

Foo bar;
Bar crazy(bar);
std::cout <<  crazy + bar << std::endl;

因为 crazy 是一个 l-value 但您将无法执行 Bar(5) + horse Foo(5) + 马

关于c++ - "Polymorphic"非成员函数/运算符,我需要额外的重载吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36041028/

相关文章:

reference - 签名中的 SML 多态引用

java - 作为父类(super class)返回时子类数据的安全性

c++ - 在 C++ 中调用带括号的枚举/枚举类时发生了什么?

c++ - msvc 2017 中的错误 C3489 不正确?

C++,函数参数中的右值引用

c++ - C++中的 'retain state'是什么意思?

c++ - 需要 Meyers Effective C++ Widget 右值实例讲解

C++11线程修改std::list

构造函数中的 C++ std::vector

c++ - 如何修改openCV中的部分多维矩阵?