【问题标题】:C++: Reuse operator+() in derived classC++:在派生类中重用 operator+()
【发布时间】:2021-06-16 09:47:31
【问题描述】:

有没有办法重用基类的operator+(...) 方法,类似于下面示例中使用赋值运算符operator=(...) 的方式?

重要提示:我不想使用抽象类/虚拟方法,我只是对下面的示例感到好奇,以便我完全理解继承的“基本”用法,而无需过多介绍多态性!在下面的例子中,operator=()这样使用就可以成功,用operator+()可以吗?

基类:

class Vector
{
private:
  int _x;
  int _y;
protected:

  // constructors & destructors here

  Vector& operator=(const Vector& source){...}

  Vector operator+(const Vector& source) const{...}

};

派生类:

class Position : public Vector
{
private:
  double _rho;
  double _phi;
public:

  // constructors & destructor here

  Position& operator=(const Position& source)
  {
    Vector::operator=(source); // slices source to its base-class part
    _rho = source._rho;
    _phi = source._phi;
    return *this;
  }

  Position operator+(const Position& source) const
  {
    /* 
    * HELP NEEDED HERE:
    * Some way of calling Vector::operator+() to avoid
    * code repetition and ensure consistency with the 
    * operator+ definition in the base class
    */
  }
};

谢谢

【问题讨论】:

    标签: c++ inheritance operator-overloading


    【解决方案1】:

    我最初的评论虽然有点轻率,但仍然适用。话虽如此,我将您的问题重新实现为可以编译以演示解决方案的内容。

    首先,您的类(如图所示)不需要赋值运算符重载。它也不需要复制构造函数、析构函数、移动构造函数或移动赋值运算符。这是因为你没有持有任何动态的东西,因此内置的浅拷贝/分配就足够了。

    话虽如此,我以稍微惯用的方式重新实现了您的operator+()。如果你能做到Derived + Derived,人们也希望能做到Derived += Derived

    因为这些是相互关联的,所以可以实现operator+() operator+=()。唯一的技巧是利用按值传递。

    代码如下:

    #include <iostream>
    
    class Base {
     public:
      Base() = default;
      Base(int x, int y) : m_x(x), m_y(y) {}
    
      // Assignment operator not required, Rule of 0
    
      Base& operator+=(const Base& rhs) {
        m_x += rhs.m_x;
        m_y += rhs.m_y;
    
        return *this;
      }
    
      friend Base operator+(Base lhs, const Base& rhs) {
        lhs += rhs;
    
        return lhs;
      }
    
     // Needed to print a Derived object
     protected:
      int getX() const { return m_x; }
      int getY() const { return m_y; }
    
     private:
      int m_x = 0;
      int m_y = 0;
    };
    
    class Derived : public Base {
     public:
      Derived() = default;
      Derived(double rho, double phi) : Base(), m_rho(rho), m_phi(phi) {}
      Derived(int x, int y, double rho, double phi)
          : Base(x, y), m_rho(rho), m_phi(phi) {}
    
      Derived& operator+=(const Derived& other) {
        Base::operator+=(other);
        m_rho += other.m_rho;
        m_phi += other.m_phi;
    
        return *this;
      }
    
      friend Derived operator+(Derived lhs, const Derived& rhs) {
        lhs += rhs;
    
        return lhs;
      }
    
      friend std::ostream& operator<<(std::ostream& sout, const Derived& rhs) {
        return sout << "x: " << rhs.getX() << "\ny: " << rhs.getY()
                    << "\nrho: " << rhs.m_rho << "\nphi: " << rhs.m_phi;
      }
    
     private:
      double m_rho = 0.0;
      double m_phi = 0.0;
    };
    
    int main() {
      Derived d1;
      Derived d2(2, 2, 1.1, 1.1);
    
      Derived d3 = d1 + d2;
      Derived d4 = d2 + d3;
      std::cout << "\nd4:\n" << d4 << '\n';
    
      std::cout << "\nd3:\n" << d3 << '\n';
    
      std::cout << "\nd2:\n" << d2 << '\n';
    }
    

    输出:

    d4:
    x: 4
    y: 4
    rho: 2.2
    phi: 2.2
    
    d3:
    x: 2
    y: 2
    rho: 1.1
    phi: 1.1
    
    d2:
    x: 2
    y: 2
    rho: 1.1
    phi: 1.1
    

    你可以看到我做“同样的事情”。在我的operator+=() 中,我首先调用Base 版本。然后我会照顾Derived 成员。这是因为operator+=() 返回一个引用,operator+() 按值获取其lhs 参数,这意味着它是一个副本。该副本由operator+=() 更改并返回。利用按值传递允许我使用operator+=(),而无需更改任何一个原始操作数。所以operator+() 仍然按预期运行。

    【讨论】:

    • 非常感谢 sweenish。首先在您的评论中,我知道复制构造函数和赋值运算符不是必需的,我不想使用动态变量过于复杂。我喜欢你的回答,非常感谢你的努力。但是,有没有办法将 operator+ 实现为真正的成员方法而不是友元方法?我想我的全部疑问是关于如何在派生类本身上使用成员函数而不将其作为参数传递。这可能吗?
    • 在两种实现运算符重载的三种方式中,最不推荐 operator+() 将其作为成员函数。请参阅this page 上的“二元算术运算符”部分。任何实现operator+() 并将所需行为作为成员函数的解决方案都可能不如这个优雅。值得注意的是,我没有为Base 以同样的方式实现operator&lt;&lt;() 的麻烦,因为我根本对打印Basees 不感兴趣。
    • 很好的参考谢谢。但是再次围绕我的问题唠叨(出于学习目的)我将如何将基类中的 + 运算符称为派生类的成员方法?我知道这是不正确的,但类似于 this->Base::operator+(...)。如果你像 operator+() 那样调用它,它最终会成为一个递归调用。你懂我的意思吗?谢谢!
    • 您将复制this,进行添加,然后返回副本。
    猜你喜欢
    • 1970-01-01
    • 2018-11-15
    • 2017-09-14
    • 2019-11-05
    • 1970-01-01
    • 2017-06-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    相关资源
    最近更新 更多