为什么非成员函数不能用于重载赋值运算符?

发布于 2024-09-27 23:18:14 字数 574 浏览 0 评论 0原文

可以使用成员函数重载赋值运算符,但不能使用非成员 friend 函数:

class Test
{
    int a;
public:
    Test(int x)
        :a(x)
    {}
    friend Test& operator=(Test &obj1, Test &obj2);
};

Test& operator=(Test &obj1, Test &obj2)//Not implemented fully. just for test.
{
    return obj1;
}

它会导致以下错误:

错误 C2801:“operator =”必须是非静态成员

为什么不能使用 friend 函数来重载赋值运算符?编译器允许使用 friend 重载其他运算符,例如 +=-=。支持 operator= 的固有问题/限制是什么?

The assignment operator can be overloaded using a member function but not a non-member friend function:

class Test
{
    int a;
public:
    Test(int x)
        :a(x)
    {}
    friend Test& operator=(Test &obj1, Test &obj2);
};

Test& operator=(Test &obj1, Test &obj2)//Not implemented fully. just for test.
{
    return obj1;
}

It causes this error:

error C2801: 'operator =' must be a non-static member

Why cannot a friend function be used for overloading the assignment operator? The compiler is allowing to overload other operators such as += and -= using friend. What's the inherent problem/limitation in supporting operator=?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

情愿 2024-10-04 23:18:14

首先,应该注意的是,这与具体实现为朋友的操作员无关。它实际上是将复制赋值实现为成员函数或非成员(独立)函数。该独立函数是否成为友元完全无关:可能是,也可能不是,具体取决于它想要在类内访问什么。

现在,这个问题的答案在 D&E 书中给出了(C++ 的设计与演化 )。原因是编译器总是为类声明/定义成员复制赋值运算符(如果您没有声明自己的成员复制赋值运算符)。

如果语言还允许将复制赋值运算符声明为独立(非成员)函数,则最终可能会得到以下结果

// Class definition
class SomeClass {
  // No copy-assignment operator declared here
  // so the compiler declares its own implicitly
  ...
};

SomeClass a, b;

void foo() {
  a = b;
  // The code here will use the compiler-declared copy-assignment for `SomeClass`
  // because it doesn't know anything about any other copy-assignment operators
}

// Your standalone assignment operator
SomeClass& operator =(SomeClass& lhs, const SomeClass& rhs);

void bar() {
  a = b;
  // The code here will use your standalone copy-assigment for `SomeClass`
  // and not the compiler-declared one 
}

如上例所示,复制赋值的语义将在翻译单元的中间发生变化- 在声明独立运算符之前,使用编译器的版本。声明后,将使用您的版本。程序的行为将根据您放置独立复制赋值运算符的声明的位置而改变。

这被认为是不可接受的危险(确实如此),因此 C++ 不允许将复制赋值运算符声明为独立函数。

确实,在您的特定示例中,恰好专门使用了 friend 函数,该运算符很早就在类定义中声明了(因为这就是声明友元的方式)。因此,在您的情况下,编译器当然会立即知道您的运算符的存在。然而,从 C++ 语言的角度来看,一般问题与友元函数没有任何关系。从C++语言的角度来看,这是关于成员函数与非成员函数的问题,并且出于上述原因完全禁止复制赋值的非成员重载。

Firstly, it should be noted that this has nothing to do with the operator being implemented as a friend specifically. It is really about implementing the copy-assignment as a member function or as a non-member (standalone) function. Whether that standalone function is going to be a friend or not is completely irrelevant: it might be, it might not be, depending on what it wants to access inside the class.

Now, the answer to this question is given in D&E book (The Design and Evolution of C++). The reason for this is that the compiler always declares/defines a member copy-assignment operator for the class (if you don't declare your own member copy-assignment operator).

If the language also allowed declaring copy-assignment operator as a standalone (non-member) function, you could end up with the following

// Class definition
class SomeClass {
  // No copy-assignment operator declared here
  // so the compiler declares its own implicitly
  ...
};

SomeClass a, b;

void foo() {
  a = b;
  // The code here will use the compiler-declared copy-assignment for `SomeClass`
  // because it doesn't know anything about any other copy-assignment operators
}

// Your standalone assignment operator
SomeClass& operator =(SomeClass& lhs, const SomeClass& rhs);

void bar() {
  a = b;
  // The code here will use your standalone copy-assigment for `SomeClass`
  // and not the compiler-declared one 
}

As seen in the above example, the semantics of the copy-assignment would change in the middle of the translation unit - before the declaration of your standalone operator the compiler's version is used. After the declaration your version is used. The behavior of the program will change depending on where you put the declaration of your standalone copy-assignment operator.

This was considered unacceptably dangerous (and it is), so C++ doesn't allow copy-assignment operator to be declared as a standalone function.

It is true that in your particular example, which happens to use a friend function specifically, the operator is declared very early, inside the class definition (since that's how friends are declared). So, in your case the compiler will, of course, know about the existence of your operator right away. However, from the point of view of C++ language the general issue is not related to friend functions in any way. From the point of view of C++ language it is about member functions vs. non-member functions, and non-member overloading of copy-assignment is just prohibited entirely for the reasons described above.

稍尽春風 2024-10-04 23:18:14

因为编译器提供的默认 operator= (成员复制)始终优先。也就是说,你的朋友 operator= 永远不会被调用。

编辑:这个答案正在回答

支持 = 运算符的固有问题/限制是什么?

问题的一部分。这里的其他答案引用了标准中说你不能这样做的部分,但这很可能就是标准的该部分以这种方式编写的原因。

Because the default operator= provided by the compiler (the memberwise copy one) would always take precedence. I.e. your friend operator= would never be called.

EDIT: This answer is answering the

Whats the inherent problem/limitation in supporting = operator ?

portion of the question. The other answers here quote the portion of the standard that says you can't do it, but this is most likely why that portion of the standard was written that way.

清音悠歌 2024-10-04 23:18:14

因为有一些运营商必须是会员。这些运算符是:
运算符[]
运算符=
运算符()
operator->

和类型转换运算符,如operator int

尽管有人可能能够准确地解释为什么运算符 = 必须是成员,但他们的论点不能适用于列表中的其他人,这使我相信“​​为什么”的答案是“只是因为”。

华泰

Because there are some operators which MUST be members. These operators are:
operator[]
operator=
operator()
operator->

and type conversion operators, like operator int.

Although one might be able to explain why exactly operator = must be a member, their argument cannot apply to others in the list, which makes me believe that the answer to "Why" is "Just because".

HTH

醉殇 2024-10-04 23:18:14

$13.5.3 - “赋值运算符应由只有一个参数的非静态成员函数来实现。因为如果用户未声明,则为类隐式声明复制赋值运算符operator=(12.8),因此基类赋值运算符总是被派生类的复制赋值运算符隐藏。”

$13.5.3 - "An assignment operator shall be implemented by a non-static member function with exactly one parameter. Because a copy assignment operator operator= is implicitly declared for a class if not declared by the user (12.8), a base class assignment operator is always hidden by the copy assignment operator of the derived class."

白龙吟 2024-10-04 23:18:14

operator= 是一个特殊的成员函数,如果您不自己声明,编译器将提供它。由于 operator= 的这种特殊状态,要求它成为成员函数是有意义的,因此不可能同时存在编译器生成的成员 operator=和用户声明的朋友 operator= 并且无法在两者之间进行选择。

operator= is a special member function that the compiler will provide if you don't declare it yourself. Because of this special status of operator= it makes sense ro require it to be a member function, so there is no possibility of there being both a compiler-generated member operator= and a user-declared friend operator= and no possibility of choosing between the two.

冷…雨湿花 2024-10-04 23:18:14

为什么友元函数不能用于重载赋值运算符?

简短回答:只是因为

更长的答案:这就是修复语法的方式。一些运算符必须是成员函数。赋值运算符是其中之一,

Why friend function can't be used for overloading assignment operator?

Short answer: Just because.

Somewhat longer answer: That's the way the syntax was fixed. A few operators have to be member functions. The assignment operator is one of the,

嗳卜坏 2024-10-04 23:18:14

operator= 的目的是对当前对象进行赋值操作。那么 LHS 或左值是相同类型的对象。

考虑 LHS 是整数或其他类型的情况。这是由operator int() 或相应的operator T() 函数处理的情况。因此,LHS 的类型已经定义,但非成员 operator= 函数可能会违反这一点。

因此它被避免了。

The intention of operator= is an assignment operation to the current object. Then the LHS, or lvalue, is an object of the same type.

Consider a case where the LHS is an integer or some other type. That is a case handled by operator int() or a corresponding operator T() function. Hence the type of the LHS is already defined, but a non-member operator= function could violate this.

Hence it is avoided.

烈酒灼喉 2024-10-04 23:18:14

因为类中已经有'='的隐式运算符重载函数来进行浅复制。因此,即使您使用友元函数进行重载,您也永远无法调用它,因为我们所做的任何调用都会调用隐式浅复制方法,而不是重载的友元函数。

Because there is already an implicit operator overloading function for '=' in the class to do shallow copying. So even if you overload using a a friend function you will never be able to call it as any call made by us would call the implicit shallow copying method rather than the overloaded friend function.

转角预定愛 2024-10-04 23:18:14

本文适用于 C++11

为什么有人想要非成员 operator=?好吧,使用成员 operator= 则可以使用以下代码:

Test const &ref = ( Test() = something ); 

它创建一个悬空引用。非成员运算符可以修复此问题:

Test& operator=(Test &obj1, Test obj2)

因为现在纯右值 Test() 将无法绑定到 obj1。事实上,这个签名将强制我们永远不会返回悬空引用(当然,除非我们提供了一个悬空引用)——该函数总是返回一个“有效”左值,因为它强制使用左值进行调用。

然而,在 C++11 中,现在有一种方法可以指定只能在左值上调用成员函数,因此您可以通过编写成员函数来实现相同的目标:

Test &operator=(Test obj2) &
//                        ^^^

现在,上面带有悬空引用的代码将无法编译。


注意。 operator= 应通过值或 const 引用获取右侧。在实现复制和交换习惯用法时,按值获取非常有用,用于轻松编写安全(但不一定是最快)复制赋值和移动赋值运算符的技术。

This post applies to C++11

Why would someone want a non-member operator=? Well, with a member operator= then the following code is possible:

Test const &ref = ( Test() = something ); 

which creates a dangling reference. A non-member operator would fix this:

Test& operator=(Test &obj1, Test obj2)

because now the prvalue Test() will fail to bind to obj1. In fact this signature would enforce that we never return a dangling reference (unless we were supplied with one, of course) - the function always returns a "valid" lvalue because it enforces being called with an lvalue.

However in C++11 there is now a way to specify that a member function can only be called on lvalues, so you could achieve the same goal by writing the member function:

Test &operator=(Test obj2) &
//                        ^^^

Now the above code with dangling reference will fail to compile.


NB. operator= should take the right-hand-side by either value or const reference. Taking by value is useful when implementing the copy and swap idiom, a technique for easily writing safe (but not necessarily the fastest) copy-assignment and move-assignment operators.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文