如何在抽象类中声明重载运算符并在派生的非抽象类中重写它?

Mic*_*lis 5 c++ polymorphism abstract-class operator-overloading

我正在尝试编写一个带有一些纯虚拟二元运算符的抽象类,它应该由派生类实现,以实现运算符多态性.这是一个简化的例子:

class Base {
public:
    virtual const Base& operator+ (const Base&) const = 0;
};

class Derived : public Base {
public:
    const Derived& operator+ (const Derived&) const;
};

const Derived& Derived::operator+ (const Derived& rvalue) const {
    return Derived();
}
Run Code Online (Sandbox Code Playgroud)

现在操作符的作用并不重要,重要的部分是它返回的内容:它返回一个临时的Derived对象或对它的引用.现在,如果我尝试编译,我得到这个:

test.cpp: In member function ‘virtual const Derived& Derived::operator+(const Derived&) const’:
test.cpp:12:17: error: cannot allocate an object of abstract type ‘Derived’
test.cpp:6:7: note:   because the following virtual functions are pure within ‘Derived’:
test.cpp:3:22: note:    virtual const Base& Base::operator+(const Base&) const
Run Code Online (Sandbox Code Playgroud)

怎么了?是不是操作符+(Base中唯一的纯虚函数)被覆盖?为什么Derived也应该是抽象的?

Igo*_* R. 6

虽然返回类型Derived可以与基础类型共同变化,但是您不能对参数类型执行相同的操作.即,重写函数应如下所示:

class Derived : public Base 
{ 
public: 
    const Derived& operator+ (const Base&) const; 
}; 
Run Code Online (Sandbox Code Playgroud)


Mar*_*tin 4

对于普通的抽象类来说,这种重载是不可能以干净的方式实现的。首先:您应该将 + 声明为非成员重载运算符作为成员函数还是非成员(友元)函数?

如果您确实需要此功能,最好的方法是从模板化接口继承:

template<typename T>
class AddEnabled {
  public:
    friend T operator+ (T const& left, T const& right) {
      return left+=right;
    }
};
Run Code Online (Sandbox Code Playgroud)

现在你写

class Foo: public AddEnabled<Foo>{
  Foo():mVal(0){
  }

  Foo& operator+=(Foo const& foo){
    mVal+=foo.mVal;
  }

 private:
  int mVal;
}
Run Code Online (Sandbox Code Playgroud)

如果您注释掉, Foo& operator+=(Foo const& foo){您将收到编译器错误,指出该运算符未实现。如果您想了解更多有关相关原理的信息,请查找http://en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trickhttp://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

HTH,马丁