My understanding of friend functions - c++

Sometimes a non-member function may need access to the private members it's taking in as a agrument.
A friend function is a non-member function that gives private access to the classes it's friends with.
Class X{
int number;
public:
X& operator+=(const X& rhs);//a += b is a.operator(b)
friend int& operator+=(int& addthis, const X& rhs);//add this += b is I don't know what lol
}
X& operator+=(const X& rhs){
this->number = this->number + rhs.number;
}
int& operator+=(int& addthis, const X& rhs){
addthis = addthis + rhs.number;
return *this;
}
What I read is that if I wanted to do += to an object, object += int, just overload the += operator, but what if the int came before the object. Say int += object? Than I would have to write it as a friend function, and that's where I get a little lost. Why can't I just write int& operator+=(int& addthis, const X& hrs); as a member function? I assume a friend function can work with other classes since it's a non-member function, so it's not assigned to any specific class?
I'm sorry I just don't understand why I would use friend function over making it a member function. Really would appreciate any feedback, thank you.

You can enable the operator+= for int and other integral types via a user-defined conversion in your class X:
struct X{
int number;
operator int() const
{
return number;
}
//...
}
Of course, this doesn't give you exactly the same behaviour as your friend-approach, as other functions could also use the conversion. Nevertheless, I guess this is what you are looking for, as otherwise you would need to define as well operator-=, operator*= and so on.

As far as I understand, you can't have operator*, operator+ or operator+= or any of operator# where # is some math operator that returns something other than an instance of your class right in the definition of your class.
In real world, it would be quite odd to add an integer to an integer and get an apple as a result. The same should apply to classes in C++. A member function is, well, a property of the class, a function that represents whatever can be done to the object of this class. Operators are special. They represent operations that sort of can't be made easier (what will you use to code an addition operator using the + sign instead of operator overloading?). They represent the very basic operations and thus should return an instance of the class they're members of.

Consider you implemented operator overloading as member function and performed something like x += y where both x and y are objects of the class which has the operator += overloaded.
Compiler parses x += y as x.operator+=(y) which is fine as both operands x and y are of the same class which has the operator += overloaded.
Now consider an expression like 2 += y (this may be insane, but I am trying explain why operator overloading with friend functions may be at time beneficial over operator overloading with member functions)
Since, the expression 2 += y will be parsed by compiler as 2.operator+=(y), an error is raised. Maybe 2 may get converted to an object of the class using constructor for conversion; (Single argument constructors can be used for conversion) but that is not the point here.
Using friend function to overload the operator calls the above expression 2 += y as operator+=(2, y) which works fine.

The reason why the operator int += X has to be a free function is that the compiler only searches for applicable member operators in the lhs type, and not in the rhs type. Since int is not a type that can be extended, you can't define this operator as a member function.
You were almost there, just a few errors:
class X;
int operator+=(int addthis, const X& rhs);
class X{
int number;
public:
X& operator+=(const X& rhs);//a += b is a.operator(b)
friend int operator+=(int addthis, const X& rhs);//add this += b is I don't know what lol
};
X& X::operator+=(const X& rhs){
this->number = this->number + rhs.number;
return *this;
}
int operator+=(int addthis, const X& rhs){
addthis = addthis + rhs.number;
return addthis;
}
some forward declarations added
int passed by value instead of by reference
missing semicolon after class declaration
class instead of Class
return corrected
Note that X += int is a member function, while int += X is a free function, declared a friend of the class X.
Using a free function for int += X is the only solution that allows to use the operator as usual, like:
X x;
int i = 2;
i += x;

The friend modifier is just meant to expose private data. Normally, you wouldn't define a friend function as a non-member if it only depends on the private data of a class it can be defined as a member function for.
A better example would be ostream::operator<< or istream::operator>>.

Related

Systematic approach of how to think about operator overloading

I'm learning how to do operator overloading and trying to come up with a systematic approach of how to know number of arguments an overloaded operator should take in and if the function should be constant.
I know the system is not perfect and doesn't catch all the edge cases, but I'm thinking that will work itself out with some logical thinking in the end.
What I'm looking for is if this systematic approach is catching the majority of cases, or am I missing something important?
Systematic approach
Important: Think logically through the entire process regarding if the input paramters can be const, * or &.
Is the operator overloader a member function and NOT a stream?* It should take 1 argument which is the value/object to the right of the operator, UNLESS it is a unary operator then it should take 0 arguments.
Does it alter the class object? If it does, add const to the end of it.
Is the operator overloader a member function and ALSO a stream?* It should take 2 arguments, first a reference to the stream object and secondly (most likely) a reference to the class object.
Does it alter the class object? If it does, add const to the end of it.
Is the operator overloader NOT a member function?* In that case it should take 2 arguments which is the value/object to the left and right of the operator, UNLESS it is a unary operator then it should take 1 argument. No const at the end needed.
Below is the header file that I based the system on.
Vector.h
#pragma once
#include <iostream>
class Vector
{
public:
Vector(double x = 0.0, double y = 0.0);
Vector& operator+=(Vector const& other);
Vector& operator-=(Vector const& other);
Vector& operator*=(double other);
Vector& operator/=(double other);
Vector operator-() const;
bool operator==(Vector const& other) const;
bool operator!=(Vector const& other) const;
double operator*(Vector const& rhs) const;
double length() const;
friend std::ostream& operator<<(std::ostream& os, Vector const& other);
friend std::istream& operator>>(std::istream& is, Vector& other);
private:
double x;
double y;
};
Vector operator+(Vector const& lhs, Vector const& rhs);
Vector operator-(Vector const& lhs, Vector const& rhs);
Vector operator*(Vector const& lhs, double rhs);
Vector operator*(double lhs, Vector const& rhs);
Vector operator/(Vector const& lhs, double rhs);
You got one thing wrong:
friend std::ostream& operator<<(std::ostream& os, Vector const& other);
You say this is written with two explicit arguments "because one of them is a stream." But actually it takes two explicit arguments because the friend keyword on the front implies this is a free function, not a member function. So it's covered by your third rule, and your second rule should be deleted entirely.
Its both less and more diverse than you sketched.
More diverse because your systematic approach misses some operators. operator() and, since C++23, operator[] can have arbitrary number of arguments. ++ and -- have an argument merely to distinguish between post and pre de/increment.
Less diverse, because your confusion seems to be mainly related to operators declared as friends defined inside the class definition. And friend / free function or member and number of arguments isn't really specific to operator overloading.
Whether a free function is a friend and defined in the class definition has some impact on ADL. Though, operators as friends are not much different than other free functions as friends. For example:
struct foo {
friend void do_something(foo) {}
};
struct bar {};
void do_something(bar) {}
int main() {
do_something(foo{});
do_something(bar{});
}
Two classes, foo and bar, and for both there is a free function called do_something. It is important to note that the do_something defined in foo is not a member of foo. I may look rather similar to a member function definition but it is none. ADL aside (which is the reason we can actually call do_something(foo{})), the only reason we would prefer making do_something a friend is when it needs access to private members. And thats the same for operator overloads.
Now consider the difference between a free function and a member function:
struct moo {
int x;
void print_x() const { std::cout << x; }
};
void print_x(const moo& m) { std::cout << m.x; }
They both do exactly the same thing. Both need an object to be called. One is called like this m.print_x(); the other is called like this print_x(m);.
Ergo, the number of parameters does not depend on whether it is a friend of the class. A member function needs one argument less than a free function that does the same.
For the rest I refer you to https://en.cppreference.com/w/cpp/language/operators. Most importantly it has a list that tells you (among other things) which operators can be overloaded as free function and which operators can only be overloaded as members. For those that can be free functions you need to decide: Free function or member. If you go for free function and it needs access to private members, you must make it a friend.
Overloads for std::ostreams << are somewhat special. Or actually not that special, you just need to consider that you are overloading an operator of std::ostream not one of your class. Because you cannot add a member to std::ostream such overloads can only be free functions.
Regarding const the usual applies. If it can be const, make it const.

Lambda expression for operator overloading

Is it possible to write lambda expression for overloading operators?
For example, I have the following structure:
struct X{
int value;
//(I can't modify this structure)
};
X needs == operator
int main()
{
X a = { 123 };
X b = { 123 };
//[define equality operator for X inside main function]
//if(a == b) {}
return 0;
}
== operator can be defined as bool operator==(const X& lhs, const X& rhs){...}, but this requires adding a separate function, and my comparison is valid only within a specific function.
auto compare = [](const X& lhs, const X& rhs){...} will solve the problem. I was wondering if I can write this lambda as an operator.
Is it possible to write lambda expression for overloading operators?
No.
Operator overload functions must be functions or function templates. They can be member functions, member function templates, non-member functions, or non-member function templates. However, they cannot be lambda expressions.
From the C++11 Standard/13.5 Overloaded operators, para 6:
An operator function shall either be a non-static member function or be a non-member function and have at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration.

Operator overloading for primitive types in C++

In C++, if you've got a class Foo, and you want users of Foo to be able to write:
Foo x;
x += 3;
, you can simply make a member function of Foo, Foo& operator+=(int rhs). If you want to be able to write:
Foo x;
int y = 3;
y += x;
, you cannot accomplish this by writing a member function of Foo, instead one has to write an external function, which usually must be declared as a friend of Foo.
How hard would it be for a future version of C++ to say that this can be written with a Foo member function int& operator+=(int &lhs, Reversed), where Reversed was some empty class whose sole purpose was to distinguish the two versions of the operator?
If this were done, it could probably eliminate the vast majority of the uses of the friend keyword in new code.
You can in fact define such an operator, because you are free to overload += for built-in types:
int& operator+=(int &lhs, Foo &rhs) {
lhs += rhs.somefield;
return lhs;
}
On the other hand, instead of writing overloaded functions for all possible operators, you can also provide a function that will allow implicit casts of class Foo to int:
class Foo {
... somefield;
operator int() {
return (int)somefield;
}
};

Why must (), [], ->, and = be overloaded only as member functions? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
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?
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;
}
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;
}
};
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.

Overloading Arithmetic Operators

The assignment operator can be declared as
T& operator= (const t&);
in a class, but the arithmetic operators cannot be defined that way. It has to be friend function. I don't understand why? Can you please explain ?
It is not mandatory that arithmetic operators should be friend
Well you can define like this:
MyClass MyClass::operator + (const MyClass& t) const
{
MyClass ret(*this);
ret += t;
return ret;
}
The a + b is really a syntax sugar, the compiler will expand it to a.operator+(b). The previous sample will work if all your objects are MyClass instances, but will not work if you have to operate with others types, ie 1 + a, will not work, this can be solved by using friends.
MyClass operator + (int i, const MyClass& t)
{
MyClass ret(i);
ret += t;
return ret;
}
This has to be done when the left hand side of the + operator is not a class, or it is a class but you can't add operator + to its definition.
I think that C++ FAQ Lite will give you a definitive answer.
They ideally should be globals and not necessarily friends, so that you can write:
yourtype v = 1;
yourtype w = 1 + v;
Since, 1 is not an object of yourtype, if the operator+ were a member it would throw a fit. However, making it global makes it convert the 1 to yourtype and then perform the operation. Making it a friend helps to extract and manipulate the members of yourtype as required -- though not required. As an example: You can implement the member function operator+= and use it in the implementation of the operator+.
The problem is that if you do something like this:
class A
{
A& operator+(int n);
// ...
}
int main()
{
A my_var;
int integer = 1;
A + integer; // compiles
integer + A // error: no function operator+(int, A) defined
}
it will not compile.
A solution is to define operator+(int, A) and operator+(A, int) as friends of A.
As a side note, the Boost Operators library makes this process very easy.