简体   繁体   English

“多态”非成员函数/运算符,我需要额外的重载吗?

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

I want to override parent class overloaded operators but I'd like to avoid boilerplate code rewriting all non-member operators for inherited class.我想覆盖父类重载运算符,但我想避免样板代码重写继承类的所有非成员运算符。 Is it possible at all?有可能吗?

In the following example, I overloaded virtual Foo & Foo::operator+=(Foo const &) and based a free function Foo & operator+(Foo, Foo const &) out of it.在下面的例子中,我重载了virtual Foo & Foo::operator+=(Foo const &)并基于它创建了一个自由函数Foo & operator+(Foo, Foo const &) In Bar, I overrode Bar & Bar::operator+=(Foo const &) override .在 Bar 中,我覆盖了Bar & Bar::operator+=(Foo const &) override What I want is the free function to call the overriden function when I state Bar + Foo and I expect Foo as a result.我想要的是当我声明Bar + Foo并且我期望Foo作为结果时调用覆盖函数的自由函数。 I know that overloading again Bar operator+(Bar, Foo const &) solves for that particular situation but I'd like to avoid explicitly do that if possible (think about all the other operators).我知道再次重载Bar operator+(Bar, Foo const &)可以解决这种特定情况,但如果可能的话,我想避免明确这样做(考虑所有其他运算符)。 And then there's also Foo + Bar that I want to return Bar .然后还有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;
}

I expect manageable bottles as a result each time manageable bottles are involved.每次涉及可管理的瓶子时,我都希望得到可管理的瓶子。

The problem derives from object slicing that occurs when invoking该问题源于调用时发生的对象切片

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

Here, f is passed by value, which means that any additional information of subtypes of Foo are discarded.这里, f是按值传递的,这意味着丢弃Foo子类型的任何附加信息。 So the compiler just sees a Foo and is not able to call the polymorphic operator.所以编译器只看到一个Foo而不能调用多态运算符。

To prevent slicing you are forced to pass a pointer or a reference, but this would imply that you need an l-value as first operand and you can't use const because you are calling operator+= on it.为了防止切片,您被迫传递指针或引用,但这意味着您需要一个l-value作为第一个操作数,并且不能使用const因为您正在调用operator+=

So you could have所以你可以有

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

and it would work for your specific situation like:它适用于您的特定情况,例如:

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

Because crazy is an l-value but you won't be able to do Bar(5) + horse nor Foo(5) + horse .因为crazy是一个l-value但你不能做Bar(5) + horseFoo(5) + horse

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM