Confused with friendly operator overloading

K

Kelly Mandrake

Iv'e been reading tutorials and articles describeing operator
overloading as both member functions and friend functions. I don't
understand however the purpose of the friend on an operator when the
operator already has access to the private data of a class since it is
a member. So why add the keyword friend.

What I do understand is that declareing a class or function as a friend
alows the friend to access private data without accessors. And I
understand that operator overloading gives us the ability to implement
common operators such as + and = on our user defined class objects.

Can somebody explain to me why a friend operator is so special?
 
V

Victor Bazarov

Kelly said:
Iv'e been reading tutorials and articles describeing operator
overloading as both member functions and friend functions. I don't
understand however the purpose of the friend on an operator when the
operator already has access to the private data of a class since it is
a member. So why add the keyword friend.

If you declare a function a friend, it's not a member. You've been either
misinformed of the meaning and the role of the friend declaration or you
read wrong tutorials.
What I do understand is that declareing a class or function as a friend
alows the friend to access private data without accessors. And I
understand that operator overloading gives us the ability to implement
common operators such as + and = on our user defined class objects.

Can somebody explain to me why a friend operator is so special?

A non-member function has to be declared "friend" to gain access to
private members of the class.

V
 
K

Kelly Mandrake

Thanks, I already understand that declareing friend gives the non
member access to my private data but what confuses me is the reason for
declareing an operator as a friend such as in this example I dont see
the reason for the friend keyword

#include
using namespace std;
class threenums {
int a, b, c;
public:
threenums() {a=b=c=0;}
threenums(int x, int y, int z) {a=x; b=y; c=z;}
friend threenums operator+(threenums o1, threenums o2);
threenums operator=(threenums o2);
void display();
};
threenums operator+(threenums o1, threenums o2)
{
threenums num;
num.a = o1.a + o2.a;
num.b = o1.b + o2.b;
num.c = o1.c + o2.c;
return num;
}
threenums threenums::eek:perator=(threenums o2)
{
a = o2.a;
b = o2.b;
c = o2.c;
return *this;
}
void threenums::display()
{
cout << a << ", ";
cout << b << ", ";
cout << c << '\n';
}
int main()
{
threenums x(5, 10, 15), y(10, 15, 20), z;
x.display();
y.display();
z = x + y;
z.display();
z = x + y + z;
z.display();
z = x = y;
x.display();
y.display();
z.display();
return 0;
}
 
V

Victor Bazarov

Kelly said:
Thanks, I already understand that declareing friend gives the non
member access to my private data but what confuses me is the reason for
declareing an operator as a friend such as in this example I dont see
the reason for the friend keyword

#include
using namespace std;
class threenums {
int a, b, c;
public:
threenums() {a=b=c=0;}
threenums(int x, int y, int z) {a=x; b=y; c=z;}
friend threenums operator+(threenums o1, threenums o2);

Remove the 'friend' declaration from the class and see what the compiler
says to that.
threenums operator=(threenums o2);
void display();
};
threenums operator+(threenums o1, threenums o2)
{
threenums num;
num.a = o1.a + o2.a;
num.b = o1.b + o2.b;
num.c = o1.c + o2.c;
return num;
} [...]

V
 
R

REH

Kelly Mandrake said:
Thanks, I already understand that declareing friend gives the non
member access to my private data but what confuses me is the reason for
declareing an operator as a friend such as in this example I dont see
the reason for the friend keyword

#include
using namespace std;
class threenums {
int a, b, c;
public:
threenums() {a=b=c=0;}
threenums(int x, int y, int z) {a=x; b=y; c=z;}
friend threenums operator+(threenums o1, threenums o2);
threenums operator=(threenums o2);
void display();
};

In this example, operator+ is not a member, but a friend. If it were a
member, you would only give it one parameter because the other would be
"this."
 
K

Kelly Mandrake

Oooh...I think you finaly got through to me...

I never saw that the classname:: was missing in the operator+
definition.

I removed friend and I see that the compiler complains about haveing
more then one parameter. And it also complains about accessing private
data. From this I can gather that when declared as a friend the
operator is passed 2 parameters where it is passed only one if not a
friend. I can also gather that because it is declared as a friend, it
must be external and when I took a closer look at the definition of
operator + I see that the classname:: is missing which I did not notice
before

I think now its starting to make secne. So I must be overloading a
global operator+ and because it is not a member of my class, it must be
declared as a friend so it can access my private data and this gives
the ability to add two differnt objects because when two diff objects
are added they call the global + operator and now I can build a handler
especialy for that.

Is this correct?
 
V

Victor Bazarov

Kelly said:
Oooh...I think you finaly got through to me...

I never saw that the classname:: was missing in the operator+
definition.

I removed friend and I see that the compiler complains about haveing
more then one parameter. And it also complains about accessing private
data. From this I can gather that when declared as a friend the
operator is passed 2 parameters where it is passed only one if not a
friend. I can also gather that because it is declared as a friend, it
must be external and when I took a closer look at the definition of
operator + I see that the classname:: is missing which I did not notice
before

I think now its starting to make secne. So I must be overloading a
global operator+ and because it is not a member of my class, it must be
declared as a friend so it can access my private data and this gives
the ability to add two differnt objects because when two diff objects
are added they call the global + operator and now I can build a handler
especialy for that.

Is this correct?

Yes, pretty much. However, if you actually think about it, you don't
really need the non-member operator+ to be a friend. If you implement
the += operator (and it should be a member, since it changes the object
for which it's called), then you can implement operator+ this way:

threenums operator +(threenums const &one, threenums const& two)
{
threenums result(one);
return result += two;
}

Also, note that your operator= does not have the proper signature. The
language creates the default one with the signature

threenums& operator=(threenums const&);

and yours for whatever reason needs its argument by value and returns
its result by value. Too much Java(tm)?

Read about the advantage of passing by const reference versus passing by
value. The FAQ should be helpful there. If not, see the archives.

V
 
E

E. Robert Tisdale

Kelly said:
Thanks, I already understand that
declaring friend gives the non member access to my private data
but what confuses me is the reason for declaring an operator as a friend
such as in this example
I don't see the reason for the friend keyword.
cat example.cc
#include <iostream>

class threenums {
private:
// representation
int a, b, c;
public:
// member operators
threenums&
operator=(const threenums& o2);
threenums
operator-(const threenums& o2) const;
// friend operators
friend
threenums
operator+(const threenums& o1, const threenums& o2);
friend
std::eek:stream&
operator<<(std::eek:stream& os, const threenums& t);
// constructors
threenums(int x = 0): a(x), b(x), c(x) { }
threenums(int x, int y, int z): a(x), b(y), c(z) { }
};

inline threenums&
threenums::eek:perator=(const threenums& o2) {
a = o2.a;
b = o2.b;
c = o2.c;
return *this;
}

inline threenums
threenums::eek:perator-(const threenums& o2) const {
return threenums(a - o2.a, b - o2.b, c - o2.c);
}

inline threenums
operator+(const threenums& o1, const threenums& o2) {
return threenums(o1.a + o2.a, o1.b + o2.b, o1.c + o2.c);
}

inline std::eek:stream&
operator<<(std::eek:stream& os, const threenums& t) {
return os << t.a << ", " << t.b << ", " << t.c;
}

int
main(int argc, char* argv[]) {
threenums x(5, 10, 15), y(10, 15, 20), z = x + y;
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
std::cout << "x + y --> z = " << z << std::endl;
z = x + y + z;
std::cout << "x + y + z --> z = " << z << std::endl;
z = x = y;
std::cout << "y --> x --> z" << std::endl;
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
std::cout << "z = " << z << std::endl;
return 0;
}
g++ -Wall -ansi -pedantic -o example example.cc
./example
x = 5, 10, 15
y = 10, 15, 20
x + y --> z = 15, 25, 35
x + y + z --> z = 30, 50, 70
y --> x --> z
x = 10, 15, 20
y = 10, 15, 20
z = 10, 15, 20

Notice that I have included a new [implicit] constructor

threenums(int x = 0): a(x), b(x), c(x) { }

This allows mixed operands

y - 13

for member operator- as long as the left operand is a threenums.
For friend operator+, either operand may be an int

y + 13

or
13 + y

as long as the other operand is a threenums.
If you mean to disallow mixed operands,
you can make operator+ a member as well.
 
K

Kelly Mandrake

Very interesting, so with this method, it is realy asking the object
itself to preform its own operator+= this way the global operator does
not need access to the private data since operator+= is a member
function and has acess to its own private data.

Thanks very much for the help everyone. It all makes sence now, and I
just created two vector classes one that has x y z and one that just
has x and y values then I implemented a operator+ that can add two
difernt vector objects. Im gona try some more examples I found.

I greatly apreciate the help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,201
Messages
2,571,049
Members
47,652
Latest member
Campbellamy

Latest Threads

Top