"Polymorphic"非成员函数/运算符,是否需要额外的重载?

"Polymorphic" non-member functions/operators, do I need extra overloadings?

本文关键字:重载 Polymorphic 成员 函数 运算符 是否      更新时间:2023-10-16

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

在下面的示例中,我重载了virtual Foo & Foo::operator+=(Foo const &),并基于它Foo & operator+(Foo, Foo const &)的免费函数。在巴尔,我超越了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;

因为crazyl-value但你做不到Bar(5) + horse,也做不Foo(5) + horse