views:

237

answers:

6

Hi, Assignment operator can be overloaded using member function but not friend function. Sample code is like below.

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;
}

Causes error:

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

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

Compiler is allowing to overload other operators like +=, -= etc using friend.

Whats the inherent problem/limitation in supporting = operator ?

+12  A: 

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.

Billy ONeal
@Billy ONeal: +1: I am jealous of the clarity you have provided behind the actual reasoning.
Chubsdad
Sorry, but that just plain incorrect and doesn't make any sense. Why would the compiler's operator take precedence? For those operators that *can* be declared as standalone functions, declaring both member version and standalone version leads to *ambiguity*, not to member function "taking precedence". What is the logic behind the statement in this answer then?
AndreyT
@AndreyT and @Billy Oneal: Both of you are right, in different contexts. If the assignment was performed inside a class method, because of the lookup rules, the member function (in this case generated by the compiler) would take precedence and hide the namespace scope `operator=`. If the assignment happens outside of the class scope, then there would be ambiguity and the compiler would fail. While this cannot be tested with `operator=` it is fairly simple to generate a test with `operator+=` (or any other operator that can be implemented both as member and as free function)
David Rodríguez - dribeas
+3  A: 

Because there are some operators which MUST be members. These operators are:
operator[]
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

Armen Tsirunyan
Well, I believe that is the OP's question: *why* must they be members?
AndreyT
@AndreyT: edited
Armen Tsirunyan
And operator. cannot be overloaded at all, which can be a shame sometimes as you cannot implement a smart_reference.
CashCow
@CashCow: Stroustrup gave a profound rationale as to why it is not allowed to overload . in "The Design and Evolution of C++". There are more which cannot be overloaded, like :: .* ?: sizeof etc.
Armen Tsirunyan
+6  A: 

$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."

Chubsdad
@Chubsdad: That doesn't explain why e.g. operator [] can't be overloaded as a freestanding function, so I guess "It's just the way it is" is the most accurate answer
Armen Tsirunyan
+1 -- the point of my answer but better standard quoting backing it.
Billy ONeal
@Armen Tsirunyan: Yes. I tried to give reference to the actual quote in the Standard that talk about this aspect. Billy's and other answers give a good reason behind the same.
Chubsdad
This answer, especially the emphasized part, talks about name hiding between the *derived and base classes*. What does it have to do with the question?
AndreyT
+1  A: 

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,

sbi
+1  A: 

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.

Bart van Ingen Schenau
+7  A: 

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.

AndreyT
Can't that be caught by making such usage ambiguous?
Chubsdad
@Chubsdad: Yes, but what would be the point then? It would always be ambiguous. You wouldn't be able to use your standalone operator at all.
AndreyT
Chubsdad
@AndreyT: hmm.. that's true. I agree
Chubsdad
@Chubsdad : The Design and Evolution of C++
Prasoon Saurav
@Prasoon Saurav: Oh yes. I should have guessed that! Thanks.
Chubsdad