C++ &引用;多态性;非成员函数/运算符,是否需要额外重载?

C++ &引用;多态性;非成员函数/运算符,是否需要额外重载?,c++,c++11,polymorphism,operator-overloading,C++,C++11,Polymorphism,Operator Overloading,我想重写父类重载运算符,但我想避免为继承的类重写所有非成员运算符的样板代码。有可能吗 在下面的示例中,我重载了virtualfoo&Foo::operator+=(Foo-const&),并基于一个自由函数Foo&operator+(Foo,Foo-const&)。在Bar中,我覆盖了Bar&Bar::operator+=(Foo const&)覆盖。我想要的是,当我声明Bar+Foo时,free函数调用覆盖函数,并且我希望结果是Foo。我知道重载再次Bar操作符+(Bar,Foo const&

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

在下面的示例中,我重载了
virtualfoo&Foo::operator+=(Foo-const&)
,并基于一个自由函数
Foo&operator+(Foo,Foo-const&)
。在Bar中,我覆盖了
Bar&Bar::operator+=(Foo const&)覆盖
。我想要的是,当我声明
Bar+Foo
时,free函数调用覆盖函数,并且我希望结果是
Foo
。我知道重载再次
Bar操作符+(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(unsigned int瓶=11):瓶(瓶){}//这是故意的
虚拟空间显示(标准::ostream&out)常数{

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

Foo const operator+(Foo f, Foo const & g) {
  return f += g;
}
这里,
f
通过值传递,这意味着
Foo
子类型的任何附加信息都将被丢弃。因此编译器只看到
Foo
,无法调用多态运算符

为了防止切片,您必须传递指针或引用,但这意味着您需要一个
l值
作为第一个操作数,并且不能使用
const
,因为您正在对其调用
运算符+=

所以你本来可以

Foo const operator+(Foo& f, Foo const & g) {
  return f += g;
}
它适用于您的具体情况,如:

Foo bar;
Bar crazy(bar);
std::cout <<  crazy + bar << std::endl;
Foo-bar;
疯狂酒吧;

std::我是否可以建议添加另一个子类型的
Foo
。称之为
Baz
。然后,制定出
+=
操作符的LHS和RHS的所有组合应该发生什么的策略。我有一种感觉,这将使您的思维更加清晰。问题之一是您将操作符+和操作符+混合在一起r+=。因此(我猜想)您使用了副本作为+运算符的参数,以避免在确实需要常量引用以使多态性工作时对它们进行修改。但是您不能使用,因为+=只接受非常量引用,因为它修改了对象。
模板t运算符+(t,const Foo&f){return t+=f;}
?但请注意不要为此层次结构定义任何非模板运算符。@ChrisR。事实上,
operator+
委托给
operator+=
在two@greendiod好的,但不是当你想让多态性工作并且保持你的l值不变的时候,我也想到了t对象切片,但我离开了
f
,因为我已经尝试了
Foo const&f
,当然你是对的,它甚至不会编译。除非我在
return Foo(f)+=g;
中使用一个临时的like。使用这种方法,现在我又回到了原点(工作切片).不幸的是,如果我像你建议的那样通过引用传递
f
,我会得到非常奇怪的结果!或者我可以使用虚拟构造函数?