【问题标题】:C++ Class, What's the difference in friend operator vs outside operatorC ++类,朋友运算符与外部运算符有什么区别
【发布时间】:2012-01-19 21:39:49
【问题描述】:

当我们在一个类中定义一个运算符函数并且我们也在一个类中定义它时,那个函数不是该类的一部分。

但是,当该函数在类之外并且我们在类中将其声明为友元但未定义它时,也可以完成相同的任务。

考虑这段代码,它有两个相同的运算符定义,一个在类内,另一个在类外:

版本 1(类内部)

class MyClass
{
    // version 1 inside a class
    friend MyClass&& operator +(MyClass& a, MyClass& b)
    {
        return move(MyClass(a.x + b.x, a.y + b.y));
    }
    int x,y;

public:
    MyClass() {}
    MyClass(int,int){}
};

int main()
{
    MyClass a, b, c;
    c = a + b;
    cin.ignore();
    return 0;
}

第 2 版(类外)

class MyClass
{
      friend MyClass&& operator +(MyClass& a, MyClass& b);
    int x,y;

public:
    MyClass() {}
    MyClass(int,int){}
};

MyClass&& operator +(MyClass& a, MyClass& b)
{
    return move(MyClass(a.x + b.x, a.y + b.y));
}

int main()
{
    MyClass a, b, c;
    c = a + b;
    cin.ignore();
    return 0;
}

这两种方法有什么区别?

【问题讨论】:

  • 所有通过右值引用移动和返回都是没有意义的。
  • RValue 返回不是比按值返回更快吗?
  • 不是没有意义,而是错误的。通过引用返回本地或临时的是未定义的行为。
  • @codekiddy:不,事实上,这完全是错误的。您正在返回对局部变量的引用。而你正在将这一举动应用于临时。它已经是一个右值,所以没有必要对它使用 move。
  • @codekiddy,一般来说,你应该避免明确地自己做任何涉及&&moveforward或类似的事情。当编译器知道这样做是安全的时,它会自动做正确的事情。如果你自己做,你更有可能引入错误而不是加速任何事情。事实上,所有这些 rvalueref 的东西都是精确地引入的,这样人们就可以编写简单的代码,这些代码表面上看起来很幼稚,并且通过值传递。

标签: c++ class operator-keyword friend


【解决方案1】:

在您的情况下,两个版本都做同样的事情(实际上返回一个悬空引用,导致未定义的行为),尽管一个是 inline 而两个不是。

一般来说,其主体定义在类中的友元函数也可以使用没有限定的类成员(那些可能是静态成员,可能在基类中,因为友元函数中没有this 指针)。

这是标准中的相关文本(第 11.3 节[class.friend]):

当且仅当类是非本地类(9.8)时,才能在类的友元声明中定义函数, 函数名不合格,函数有命名空间范围。

这样的函数是隐含的inline。在类中定义的friend 函数位于定义它的类的(词法)范围内。在类外部定义的 friend 函数不是 (3.4.1)。

【讨论】:

    【解决方案2】:

    目前,您在第一个 sn-p 中定义了两次 MyClass&& operator +(MyClass& a, MyClass& b),在第二个中定义了一次。如果删除第二个定义,则两者在语义上是等价的。

    两者会做同样的事情。在某些情况下,一个可能比另一个更受欢迎(例如,第二个可以放在cpp 文件中,而第一个可能更自然地使用模板)。

    注意第一个被隐式标记为内联,第二个不是。

    (不过,您应该通过 const 引用传递 MyClass。)

    【讨论】:

    • 哦,谢谢,我已经更正了我的第一个 sn-p。那么现在这两个 sn-ps 在更正后是完全一样的吗?
    • 请注意,类体内的友元函数只能通过参数相关查找 (ADL) 找到,但不能显式限定。
    猜你喜欢
    • 2013-06-16
    • 1970-01-01
    • 2020-11-01
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多