this might be a noobie question but this confuses me, especially when it comes to this pointer.
How do I know which object "this" pointer is pointing to? I can provide an example where that confuses me... Say you had this code
#include<iostream>
using namespace std;
class someClass{
int var;
//2 constructors here, one with no arguments, one with giving a value to var(not important)
someClass operator+(someClass object){
someClass rObject;
rObject.var = this->var + object.var //and here is my problem
}
};
int main() {
someClass a(20);
someClass b(30);
someClass c;
c=a+b; //????????
//rest of the code not important
}
In this case the "current object" would be the object a, but how does that make sense if we just switch sides so it's c=b+a the current object would become b... I am confused... What determines the current object?
You have chosen the more involved example: operators. In general it is easier to reason about other member functions. Consider:
struct T {
int value;
void foo() { std::cout << this->value << '\n'; }
};
int main() {
T t;
t.foo();
}
How do you know which is the current object inside foo()? It is the object on the left of the dot operator in the expression, in this case t. (Well, in this case there is no other object at all in the program!)
Now going back to operators, for binary operators in particular, many of them can be implemented in two forms, as a free function taking two arguments or as a member function taking a single argument. There is a direct transformation that the compiler will do for you in both cases:
struct T {
int value;
T operator+(T const & rhs) { T tmp; tmp.value = this->value + rhs.value; return tmp; }
};
T operator-(T const & lhs, T const & rhs) {
T tmp; tmp.value = lhs.value - rhs.value; return tmp;
}
int main() {
T a, b; a.value = 1; b.value = 2;
a - b;
a + b;
}
Then the compiler encounters the expression a - b it searches for the two possible forms of the operator, it finds that it is a free function and it binds lhs to a and rhs to b, transforming the expression into operator-(a, b). In the case of a + b, the compiler again searches for the operator and finds it as a member function, at this point the transformation becomes a.operator+(b) and the this pointer inside the member function refers once again to the object to the left of the dot operator.
Non-static class methods have an implicit first argument this of the class type. So when you write:
operator+(someClass object)
You are actually getting this:
operator+(someClass* this, someClass object)
And now you can see: the left-hand side of a binary operator is the first argument, and the right-hand side is the second argument (by convention, and because it makes more sense than the other way around).
When you execute a+b, that invokes operator +(someClass) on object a. Therefore, this is a.
It helps to first consider an easier operator, namely operator +=. It may appear to be a more advanced operator, but that's because we learned arithmetic using +. If you look at your code, you see that you typically need three objects for + c=a+b whereas += just needs two: b += a.
Now in b += a the this pointer should point to the object you're changing, i.e. b. That's the first object. To keep things simple, for all binary operators this points to the first object.
Related
I'm doing some revision of my C++, and I'm dealing with operator overloading at the minute, specifically the "="(assignment) operator. I was looking online and came across multiple topics discussing it. In my own notes, I have all my examples taken down as something like
class Foo
{
public:
int x;
int y;
void operator=(const Foo&);
};
void Foo::operator=(const Foo &rhs)
{
x = rhs.x;
y = rhs.y;
}
In all the references I found online, I noticed that the operator returns a reference to the source object.
Why is the correct way to return a reference to the object as opposed to the nothing at all?
The usual form returns a reference to the target object to allow assignment chaining. Otherwise, it wouldn't be possible to do:
Foo a, b, c;
// ...
a = b = c;
Still, keep in mind that getting right the assigment operator is tougher than it might seem.
The return type doesn't matter when you're just performing a single assignment in a statement like this:
x = y;
It starts to matter when you do this:
if ((x = y)) {
... and really matters when you do this:
x = y = z;
That's why you return the current object: to allow chaining assignments with the correct associativity. It's a good general practice.
Your assignment operator should always do these three things:
Take a const-reference input (const MyClass &rhs) as the right hand side of the assignment. The reason for this should be obvious, since we don't want to accidentally change that value; we only want to change what's on the left hand side.
Always return a reference to the newly altered left hand side, return *this. This is to allow operator chaining, e.g. a = b = c;.
Always check for self assignment (this == &rhs). This is especially important when your class does its own memory allocation.
MyClass& MyClass::operator=(const MyClass &rhs) {
// Check for self-assignment!
if (this == &rhs) // Same object?
return *this; // Yes, so skip assignment, and just return *this.
... // Deallocate, allocate new space, copy values, etc...
return *this; //Return self
}
When you overload an operator and use it, what really happens at compilation is this:
Foo a, b, c;
a = b;
//Compiler implicitly converts this call into the following function call:
a.operator=(b);
So you can see that the object b of type FOO is passed by value as argument to the object a's assignment function of the same type. Now consider this, what if you wanted to cascade assignment and do something like this:
a = b = c;
//This is what the compiler does to this statement:
a.operator=(b.operator=(c));
It would be efficient to pass the objects by reference as argument to the function call because we know that NOT doing that we pass by value which makes a copy inside a function of the object which takes time and space.
The statement 'b.operator=(c)' will execute first in this statement and it will return a reference to the object had we overloaded the operator to return a reference to the current object:
Foo &operator=(const Foo& rhs);
Now our statement:
a.operator=(b.operator=(c));
becomes:
a.operator(Foo &this);
Where 'this' is the reference to the object that was returned after the execution of 'b.operator=(c)'. Object's reference is being passed here as the argument and the compiler doesn't have to create a copy of the object that was returned.
Had we not made the function to return Foo object or its reference and had made it return void instead:
void operator=(const Foo& rhs);
The statement would've become something like:
a.operator=(void);
And this would've thrown compilation error.
TL;DR You return the object or the reference to the object to cascade(chain) assignment which is:
a = b = c;
This is a rather simple concept. I have an arithmetic operator and I wish for the operation to update not create an object. Essentially,
MyType A;
MyType B;
MyType C;
A = B - C;
A = C - B;
The statement A = B - C should not call the constructor for MyType again since A is already created, i.e. the constructor should only be called 3 times in this program. Is there some way to achieve this while maintaining a nice syntax? I suspect that I could let the operator function know not to create an object but rather to use some reference. Is there a more streamlined way to do this using some c++ syntax unknown to me?
class MyType
{
MyType* OperatorReturnObj;
MyType operator-(const MyType& Left, const MyType& Right)
{
// This removed and replaced with SetOperatorReturnObj function
// MyType OperatorReturnObj();
OperatorReturnObj= Left - Right;
return OperatorReturnObj;
}
void MyType SetOperatorReturnObj(MyType* Ref)
{
OperatorReturnObj = Ref;
}
};
Without ugly tricks like creating pool of objects and using them internally (where complications would be more expensive than any benefits for this case), there is no way to achieve this. Problem is that statement:
A = B - C;
is equal to:
A.operator=( operator-( B, C ) );
as you can see operator-( B, C ) has to be executed first and provide result somewhere. So you either have to change syntax like:
A += B; A -= C; // or even
(A += B) -= C; // or maybe
A += B -= C;
or use regular syntax and if you need efficiency implement move semantics.
After some thought you can create object of type MyTypeExression which does not do actual calculations but remember arguments and operations and only do them later when MyType::operator=(MyTypeExression) is executed. Though for that to work you probably need a wrapper with smart pointer for MyType so MyTypeExression does not have to copy it's arguments. So this solution can be considered as complicated trick I mentioned before.
I wish for the operation to update not create an object
For A = B - C;, A will be updated, by operator=.
More particular, operator- 's return value is passed by value, a temporary variable has to be created inside operator- and then copied/moved to A.
BTW1: OperatorReturnObj= Left - Right; will cause an infinite recursion.
BTW2: MyType A(); is a function declaration indeed. Most vexing parse
You cannot.
In A = B - C, first the B - C expression is evaluated. Then the result is copied to A.
The B - C expression knows nothing about A, so it is not possible to update A directly.
You can overload the assignment operator but this will not prevent the creation of a new object.
Some tips:
First of all, you didn't specified how to initialize the internal pointer attribute, so at this moment it points to an unspecified value in the memory stack.
Second, the operator- method(!) isn't defined like you did. look at "binary arithmetic operators"
binary operators have to return a reference to the object they are called from.
Third, the object itself is passed "automagically" to its methods, and its available as the this pointer.
So you don't have to pass it as the first parameter.
Finally, to return a reference you have to return the value, and not the pointer : --> *this.
So an expression like A=B+C is evaluated to:
A.operator=(B.operator+(C))
So B+C is different than C+B. (I don't enter in the details of inheritance here..)
Inspired from the same previous link above:
class X {
int internalprivatevalue;
//....
public:
X& operator+(const X& second) {
// actual addition of second to *this takes place here
// e.g. internalprivatevalue+=second. internalprivatevalue;
return *this; // return the result by reference!!
}
}
Hope to have clarified a little more your doubts.
I realize that there are examples after examples of overloading the assignment operator on the web, but I have spent the last few hours trying to implement them in my program and figure out how they work and I just can't seem to do it and any help would be greatly appreciated.
I am trying to implement an overloaded assignment operator function.
I have 3 files working, the Complex.h header file, a Complex.cpp definition file, and a .cpp file I'm using as a driver to test my Complex class.
In the Complex.h header file my prototype for the assignment operator:
Complex &operator= (Complex&);
And so far what I have for the definition of the overloaded operator in my .cpp file is:
Complex &Complex::operator=(Complex& first)
{
if (real == first.real && imaginary == first.imaginary)
return Complex(real, imaginary);
return first;
};
And the way I'm calling my assignment operator in my functions is:
x = y - z;
So specifically, my problem is that when I call the overloaded assignment operator with x = y -z, it doesn't assign the passed in value to x when I return the passed in value and I'm unable to figure out why from numerous examples and explanations on the web, any help would be greatly appreciated and I thank you for any help ahead of time.
I think you need the following operator definition
Complex & Complex::operator =( const Complex &first )
{
real = first.real;
imaginary = first.imaginary;
return *this;
};
You have to return reference to the object that is assigned to. Also the parameter should be a constant reference. In this case you may bind the reference to a temporary object or you have to write also a move assignment operator.
In your implementation of the copy assignment operator you do not change the assigned object.:) You simply create a temporary and return reference to this temporary or return reference to first.
Assignment takes in two objects, the object to be assigned to, and the object with the desired value.
Assignment should:
modify an existing object, the object being assigned to
Assignment should not:
create a new object
modify the object that has the desired value.
So let's say the object type we're dealing with is:
struct S {
int i;
float f;
};
A function that performs assignment might have the signature:
void assignment(S &left_hand_side, S const &right_hand_side);
And it would be used:
S a = {10, 32.0f};
S b;
assignment(b, a);
Notice:
the left hand side object is modifiable, and assignment will modify it, rather than create a new object.
the right hand side object, the object with the desired value, is not modifiable.
Additionally, in C++ the built-in assignment operation is an expression rather than a statement; it has a value and can be used as a subexpression:
int j, k = 10;
printf("%d", (j = k));
This sets j equal to k, and then takes the result of that assignment and prints it out. The important thing to note is that the result of the assignment expression is the object that was assigned to. No new object is created. In the above code, the value of j is printed (which is 10, because j was just assigned the value 10 from k).
Updating our earlier assignment function to follow this convention results in a signature like:
S &assignment(S &left_hand_side, S const &right_hand_side);
An implementation looks like:
S &assignment(S &left_hand_side, S const &right_hand_side) {
// for each member of S, assign the value of that member in
// right_hand_side to that member in left_hand_side.
left_hand_side.i = right_hand_side.i;
left_hand_side.f = right_hand_side.f;
// assignment returns the object that has been modified
return left_hand_side;
}
Note that this assignment function is not recursive; it does not use itself in the assignment, but it does use assignment of the member types.
The final piece of the puzzle is getting the syntax a = b to work, instead of assignment(a, b). In order to do this, all you have to do is make assignment () a member function:
struct S {
int i;
float f;
S &assignment(S &left_hand_side, S const &right_hand_side) {
left_hand_side.i = right_hand_side.i;
left_hand_side.f = right_hand_side.f;
return left_hand_side
}
};
Replace the left_hand_side argument with *this:
struct S {
int i;
float f;
S &assignment(S const &right_hand_side) {
this->i = right_hand_side.i;
this->f = right_hand_side.f;
return *this;
}
};
And rename the function to operator=:
struct S {
int i;
float f;
S &operator=(S const &right_hand_side) {
this->i = right_hand_side.i;
this->f = right_hand_side.f;
return *this;
}
};
int main() {
S a, b = {10, 32.f};
S &tmp = (a = b);
assert(a.i == 10);
assert(a.f == 32.f);
assert(&tmp == &a);
}
Another important thing to know is that the = sign is used in one place that is not assignment:
S a;
S b = a; // this is not assignment.
This is 'copy initialization'. It does not use operator=. It is not assignment. Try not to confuse the two.
Points to remember:
assignment modifies the object being assigned to
assignment does not modify the object being assigned from.
assignment does not create a new object.
assignment is not recursive, except insofar as assignment of a compound object makes use of assignment on all the little member objects it contains.
assignment returns the object after modifying its value
copy initialization looks sort of like assignment, but has little to do with assignment.
An overloaded assignment operator should look like this:
Complex &Complex::operator=(const Complex& rhs)
{
real = rhs.real;
imaginary = rhs.imaginary;
return *this;
};
You should also note, that if you overload the assignment operator you should overload the copy constructor for Complex in the same manner:
Complex::Complex(const Complex& rhs)
{
real = rhs.real;
imaginary = rhs.imaginary;
};
There is a pre-defined class named B as under:
class B
{
protected:
A ins;
public:
void print() {
cout<<"t";
}
operator A() const {
return ins;
}
};
Can anyone please explain the meaning of the line "operator A() const" and how can this be used to fetch "ins" in the main function?
This is a conversion operator that allows B objects to be converted to (cast to) A objects.
Let's break down operator A() const {...}
It is equivalent to something like A convert_to_A() { return ins; } except that by naming it operator A the compiler can use it automatically.
operator A means that this is an operator that converts to type A.
(): conversion operators are always function that take no parameters.
const because casting a B to an A must not change the value of the B. For example:
double d = 3.14;
int i = d;
Here d has been (implicity) cast to an int. i has the value 3, but d is still 3.14 -- the conversion did not change the original value.
In the context of your code we can say:
a B object contains a hidden A object
each B is willing to "pretend" to be an A ...
... by returning a copy of the A inside it
Allowing:
void f(A an_a) {...}
B my_b;
f(my_b);
Note that the conversion operator returns a copy of ins. Depending on context, you might want to change it to operator A&() const {...} to return a reference instead of a copy (if, for example, A was an expensive class to copy). However, this would allow the caller to change the A stored inside B, which is probably not want you want. To prevent the copy, but not allow changes, you would have to return a const reference to A. This is why you'll often see:
operator const A&() const { return ins;}
This mean you can cast your B instance to A and get the ins member of B.
B b;
A a;
a = (A)b;
// a is now equal to the member `ins` of b. Depending on the implementation of operator = of class A, it was probably copied into the a variable.
I'm doing some revision of my C++, and I'm dealing with operator overloading at the minute, specifically the "="(assignment) operator. I was looking online and came across multiple topics discussing it. In my own notes, I have all my examples taken down as something like
class Foo
{
public:
int x;
int y;
void operator=(const Foo&);
};
void Foo::operator=(const Foo &rhs)
{
x = rhs.x;
y = rhs.y;
}
In all the references I found online, I noticed that the operator returns a reference to the source object.
Why is the correct way to return a reference to the object as opposed to the nothing at all?
The usual form returns a reference to the target object to allow assignment chaining. Otherwise, it wouldn't be possible to do:
Foo a, b, c;
// ...
a = b = c;
Still, keep in mind that getting right the assigment operator is tougher than it might seem.
The return type doesn't matter when you're just performing a single assignment in a statement like this:
x = y;
It starts to matter when you do this:
if ((x = y)) {
... and really matters when you do this:
x = y = z;
That's why you return the current object: to allow chaining assignments with the correct associativity. It's a good general practice.
Your assignment operator should always do these three things:
Take a const-reference input (const MyClass &rhs) as the right hand side of the assignment. The reason for this should be obvious, since we don't want to accidentally change that value; we only want to change what's on the left hand side.
Always return a reference to the newly altered left hand side, return *this. This is to allow operator chaining, e.g. a = b = c;.
Always check for self assignment (this == &rhs). This is especially important when your class does its own memory allocation.
MyClass& MyClass::operator=(const MyClass &rhs) {
// Check for self-assignment!
if (this == &rhs) // Same object?
return *this; // Yes, so skip assignment, and just return *this.
... // Deallocate, allocate new space, copy values, etc...
return *this; //Return self
}
When you overload an operator and use it, what really happens at compilation is this:
Foo a, b, c;
a = b;
//Compiler implicitly converts this call into the following function call:
a.operator=(b);
So you can see that the object b of type FOO is passed by value as argument to the object a's assignment function of the same type. Now consider this, what if you wanted to cascade assignment and do something like this:
a = b = c;
//This is what the compiler does to this statement:
a.operator=(b.operator=(c));
It would be efficient to pass the objects by reference as argument to the function call because we know that NOT doing that we pass by value which makes a copy inside a function of the object which takes time and space.
The statement 'b.operator=(c)' will execute first in this statement and it will return a reference to the object had we overloaded the operator to return a reference to the current object:
Foo &operator=(const Foo& rhs);
Now our statement:
a.operator=(b.operator=(c));
becomes:
a.operator(Foo &this);
Where 'this' is the reference to the object that was returned after the execution of 'b.operator=(c)'. Object's reference is being passed here as the argument and the compiler doesn't have to create a copy of the object that was returned.
Had we not made the function to return Foo object or its reference and had made it return void instead:
void operator=(const Foo& rhs);
The statement would've become something like:
a.operator=(void);
And this would've thrown compilation error.
TL;DR You return the object or the reference to the object to cascade(chain) assignment which is:
a = b = c;