2

I tried to analyse why some of the operators ((), [], ->, =) should be overloaded as member functions only. I failed and I tried to search on internet but of no use. Can any one please help me to understand this restriction?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
kadina
  • 5,042
  • 4
  • 42
  • 83
  • Who says == should only be a member function? – chris Mar 05 '14 at 01:23
  • Thanks Chris. I modified it. It should be = – kadina Mar 05 '14 at 01:24
  • Related: http://stackoverflow.com/q/4192580/420683 – dyp Mar 05 '14 at 01:29
  • I would guess it's related to the fact that they require their left-operands to be lvalues? (Except for `[]` I suppose). – alecbz Mar 05 '14 at 01:31
  • Thanks dyp. But that question is mostly related to only operator "=". It is not about other operators (), [], -> – kadina Mar 05 '14 at 01:34
  • How would you invoke these operators if they weren't members of a class? – Eugene S Mar 05 '14 at 01:36
  • @unluddite The same way that general overloaded operators can be invoked - by passing the left-hand argument as a first parameter. – templatetypedef Mar 05 '14 at 01:36
  • @kadina That's why I didn't mark it as a duplicate ;) – dyp Mar 05 '14 at 01:39
  • I **finally** found the duplicate I was looking for: [Why can some operators only be overloaded as member functions, other as friend functions and the rest of them as both?](http://stackoverflow.com/q/1132600/420683) – dyp Mar 05 '14 at 01:54
  • I saw the post you mentioned dyp. But I didn't understand the reasons mentioned there quite well :( – kadina Mar 05 '14 at 02:01

3 Answers3

2

Certain forms of operators require access to the "this" pointer of an instance of a class in order to operate directly on that instance as they only take a single argument to the same type.

class A{
public:

    int x;

    // only takes a reference to another 'A' type, so we need the 'this' pointer
    A& operator=(const A& other){
        this->x = other.x;
        return *this;
    }
};
mbradber
  • 489
  • 5
  • 17
  • `=` is not a unary operator. – dyp Mar 05 '14 at 01:40
  • My apologies - as a correction, the *binary* operators +, -, <<, etc. can be declared as free functions just fine. Why would = be special? – templatetypedef Mar 05 '14 at 01:41
  • @dyp Yea, I shouldn't have used the term "unary" as C++ formal classifications for those. Editing answer. – mbradber Mar 05 '14 at 01:43
  • @templatetypedef [over.unary]/1 "A prefix unary operator shall be implemented by a non-static member function (9.3) with no parameters **or a non-member function with one parameter.**" you were right that unary operators can be declared as free functions. – dyp Mar 05 '14 at 01:43
  • @templatetypedef The +, -, << operators are read only and do not modify the instance, whereas the assignment operator modifies an instance. That is the difference. – mbradber Mar 05 '14 at 01:48
  • "Unary operators require access to the "this" pointer of an instance of a class in order to operate directly on that instance.". But this may not be correct. because even we are overloading prefix or postfix operators that will change the contents of the object. But we are not overloading those as member functions. We are just passing reference to the object in case of non member functions. – kadina Mar 05 '14 at 01:49
  • @mbradber `operator <<` definitely modifies the lhs if used for stream insertion, though. You can also define operators like `+=` as free functions, and they also modify the lhs. I'm not sure that argument works here. – templatetypedef Mar 05 '14 at 01:49
2

Although maybe not very satisfying, here's what the standard has to say about it:

(emphasis is mine)

§3.5.3 Assignment

An assignment operator shall be implemented by a non-static member function with exactly one parameter.

§3.5.4 Function call

operator() shall be a non-static member function with an arbitrary number of parameters.

§3.5.5 Subscripting

operator[] shall be a non-static member function with exactly one parameter.

§3.5.6 Class member acess

operator-> shall be a non-static member function taking no parameters.

I can't speak to the reasoning behind these requirements, so I will leave that aspect to those that are more familiar with how compilers are designed.

Eugene S
  • 3,092
  • 18
  • 34
2

I think this is most likely why that portion of the standard was written that way.

but if it is not forbidden, the friend version would never be called, in my testing code ,when

 Complex operator+(const Complex &other);

is defined as private, the compiler would give error message

‘Complex Complex::operator+(const Complex&)’ is private
 Complex Complex::operator+(const Complex &other)

instead of using the friend version

refer to Why cannot a non-member function be used for overloading the assignment 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.

(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)

I try to using operator + for test. it prove the precedence

it outputs:

member function called
7+11i

testing code:

#include<iostream>
using namespace std;
class Complex
{
public:
    Complex(int real, int imag);
    Complex(void);
    ~Complex(void);

    Complex &Add(const Complex &other);

    void Display() const;

    Complex operator+(const Complex &other);

    friend Complex operator+(const Complex &c1, const Complex &c2);

private:
    int real_;
    int imag_;
};
Complex::Complex(int real, int imag): imag_(imag), real_(real)
{

}
Complex::Complex(void)
{
}

Complex::~Complex(void)
{
}

Complex &Complex::Add(const Complex &other)
{
    real_ += other.real_;
    imag_ += other.imag_;
    return *this;
}


void Complex::Display() const
{
    cout << real_ << "+" << imag_ << "i" << endl;
}


Complex Complex::operator+(const Complex &other)
{
    int r = real_ + other.real_;
    int i = imag_ + other.imag_;
    std::cout << "member function called"<< std::endl;
    return Complex(r, i);
}

Complex operator+(const Complex &c1, const Complex &c2)
{
    int r = c1.real_ + c2.real_;
    int i = c1.imag_ + c2.imag_;
    std::cout << "friend function called"<<std::endl;
    return Complex(r, i);
}

int main(void)
{
    Complex c1(3, 5);
    Complex c2(4, 6);


    Complex c3 = c1 + c2;

    c3.Display();

    return 0;
}
Community
  • 1
  • 1
michaeltang
  • 2,850
  • 15
  • 18