【问题标题】:Operator Functions as Member Functions and Nonmember Functions作为成员函数和非成员函数的运算符函数
【发布时间】:2012-05-13 13:28:34
【问题描述】:

对于将运算符重载为成员函数和非成员函数的想法,我感到非常困惑。

当我们将运算符重载为非成员函数时,我们实际上是什么意思,同样,当我们将运算符重载为成员函数时,我们的意思是什么。虽然我知道非成员函数是 friend 函数。

【问题讨论】:

标签: c++


【解决方案1】:

如果将运算符重载为非成员函数,则需要在参数列表中指定要专门对其进行操作的对象。

如果你将它作为成员函数重载,“this”指针将为你完成部分工作。

考虑以下示例:

class Test {
   public:
   friend Test operator+(const Test &lhs, const Test &rhs); // Non-member function
   Test operator+(const Test &rhs); // Member function
};

两者之间的区别在于,非成员函数没有this 指针,当您谈论某个类的特定实例时,编译器会方便地为您传递该指针。

成员函数 one 已推断出 lhs,因此您只需提供 rhs。

请注意,“朋友”不是必需的,但如果您想访问 Test 的私人成员,则需要它。

编译器可以根据参数计数消除歧义。如果你想声明friend Test operator+(const Test &rhs),它会抱怨参数不足,因为 + 是一个二元运算符。成员函数 operator+ 的 lhs 是“this”。

【讨论】:

    【解决方案2】:

    例子

    class Foo {
    public:
      Foo operator+(Foo) // member variant
      // declared inside the function
    }; // end of class
    
    Foo operator+(Foo lhs, Foo rhs) // non-member variant
    { // declared outside the class
      // could be just a call to the member variant
      lhs.operator+(rhs);
      // I usually do this when implementing std::stream operators,
      // don't remember why just now.
    }
    

    非成员不需要成为朋友,但如果它需要访问内部状态,则可能是。 如果我没记错的话,非成员在某些编译器上的模板化代码和命名空间方面具有一些优势到这堂课。它告诉我,如果我更改该类,我可能需要查看非成员运算符以确保我没有破坏任何东西。

    【讨论】:

      【解决方案3】:

      一个小例子:(我没有尝试编译这段代码,但我希望它能工作)

      class MyClass
      {
      public:
          MyClass operator+(const MyClass& other) const; //member operator declaration
      
          friend MyClass operator-(const MyClass& first, const MyClass& second); //non-member operator friend declaration
      private:
          int _a;
      }
      
      //member operator definition
      MyClass MyClass::operator+(const MyClass& other) const
      {
          MyClass result;
          result._a = _a + other._a;
          return result;
      }
      
      //non-member operator definition
      MyClass MyClass::operator-(const MyClass& first, const MyClass& second)
      {
          MyClass result;
          result._a = first._a - second._a;
          return result;
      }
      

      注意区别:在成员运算符定义中,我没有在“=”之后的第一个 _a 之前指定任何内容 - 假定为 this->_a。

      只有当您的类的实例是运算符的第一个参数时,才能使用成员运算符函数。例如,如果您想做类似2 + myClassObject 的操作,则需要覆盖非成员运算符MyClass MyClass::operator+(int first, const MyClass& second)(或您希望它具有的任何返回值)。

      另请注意,我只需要我的非会员操作员才能访问私有 _a 字段的友谊声明。

      【讨论】:

        【解决方案4】:

        大多数运营商应该被定义为成员。

        class MyClass
        {
        ...
        public:
            const MyClass& operator+=(const MyClass&);
        };
        

        这在行为上与以下内容相同:

        class MyClass {...};
        const MyClass& operator+=(const MyClass&, const MyClass&);
        

        第一个示例中隐含的this 类似于第二个示例的第一个参数。如果第二个例子需要访问MyClass的内部状态,则需要friended。

        class MyClass
        {
            friend const MyClass& operator+=(const MyClass&, const MyClass&);
        };
        const MyClass& operator+=(const MyClass&, const MyClass&);
        

        对此的典型例外是operator<< on std::ostream

        std::ostream& operator<<(std::ostream&, const MyClass&);
        

        这在逻辑上是MyClass 的成员,但由于参数的顺序,它必须是两个类的非成员或std::ostream 的成员。因为您不能将成员添加到std::ostream,所以必须将其定义为非成员。

        【讨论】:

        • operator+ 通常返回该类型的新实例,即T operator+(const T&amp; lhs, const T&amp; rhs);。如果你返回一个引用,它应该引用什么?此外,operator+ 之类的东西通常作为非成员实现,以允许对左侧操作数进行隐式转换(如果您将运算符实现为成员,则不允许这样做)。
        猜你喜欢
        • 2011-06-05
        • 1970-01-01
        • 2010-12-26
        • 2012-02-01
        • 2013-06-29
        • 2013-11-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多