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.
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 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.
I am a beginner in C++, and this must be a really basic question. I understand & stands for referencing operation. For example, a = &b assigns the address of b to a. However, what does & in a declaration such as the following mean?
className& operator=(const className&);
Do the following make sense and what is the difference between the last line and the following?
className* operator=(const className*);
From the answers below, it seems --- as I understand it --- that the following is valid too. Is it? If it is, how is it different from the version with "&"?
className operator=(const className);
After reading the following answers and some more outside, I realized part of my original confusion stems from mixing up reference as in general computer science and reference type as in C++. Thank you all who answered my question. All the answers clarify my understanding to different degrees, even though I can only pick one as the accepted answer.
The token & has three distinct meanings in C++, two of which are inherited from C, and one of which is not.
It's the bitwise AND operator (unless overloaded).
It's the address operator, which acts on an lvalue to yield a pointer to it. (Unless overloaded.) This is what is happening in a = &b.
It denotes a reference type. const className& as a parameter is a const reference to an object of type className, so when the function is called, the argument will be passed by reference, but it won't be allowed to be modified by the function. The function you gave also returns a reference.
Assignment Operator
Understanding is best gained by example:
class A {
int x;
public:
A(int value) : x(value) {}
A& operator=(const A& from) { // Edit: added missing '=' in 'operator='
x = from.x;
return *this;
}
};
A m1(7);
A m2(9);
m2 = m1; /// <--- calls the function above, replaces m2.x with 7
Here, we defined the assignment operator. This special method is designed to provide assignment capability to objects.
The reason that it returns a reference to *this is so you can chain assignments without excessive memory copies:
A m3(11);
m3 = m1 = m2; /// <--- now, m3.x and m1.x both set to m2.x
Expanded as follows:
m3 = ( something )
where
(something) is a reference to the object m1
by result of call to m1.operator=(m2) method
such that
the returned reference is then passed into m3.operator(...)
Chaining lets you do this:
(m1=m2).function(); // calls m1.function after calling assignment operator
Libraries such as boost leverage this pattern (for a different type of chaining example, see the program options library in boost) and it can be useful when developing a domain specific 'language'.
If instead full objects were returned from operator=, the chained assignment would at a minimum involve multiple extra copies of the objects, wasting CPU cycles and memory. In many cases things would not work properly because of the copy.
Essentially, using a reference avoids a copy.
Note
In reality, (simplified explanation) a reference is just a fancy syntax for a C pointer.
In the common case, you can then write code with A.x instead of A->x.
Caution
Returning a pure reference from a method is often dangerous; newcomers can be tempted to return a reference to an object constructed locally inside the method on the stack, which depending on the object can lead to obscure bugs.
Your pointer example
It depends on what you return from the body of the method, but regardless, the following would instead return a pointer to some instance of className:
className* operator=(const className*);
This will compile and it even seems to work (if you return this from the method), but this does violate the Rule of Least Surprise, as it is likely anyone else attempting to use your code would not expect the assignment operator to return a pointer.
If you think about base types:
int x=1; int y=2; int z; z=y=x;
will never ever do anything other than return integers - so having operator= return the assigned to object is consistent)
It also doesn't let you do this:
(m1 = m2).something
It also allows you to pass NULL which is something assignment operators don't typically want to care about.
Instead of writing
blah& operator(const blah& x) { a = x.a ; return *this; }
You would need to write:
blah* operator(const blah* x) {
if (x) { a = x->a ; return this; }
else { /*handle null pointer*/
}
It means the function takes a reference to a const className and returns a reference to a className
Say you have a class like below:
class className
{
public:
className& operator=(const className& rhs)
{
this->a_ = rhs.a_;
this->b_ = rhs.b_;
return *this;
}
private:
std::string a_;
std::string b_;
};
You can use the assignment operator of the class as below:
className a;
className b;
className c;
c = b = a;
The above line is executed as:
c.operator=(b.operator=(a));
Now take another class that has the operator= defined using the second form:
class className2
{
public:
className2* operator=(const className2* rhs)
{
this->a_ = rhs->a_;
this->b_ = rhs->b_;
return this;
}
private:
std::string a_;
std::string b_;
};
You can use the assignment operator of the class as below:
className2 obj1;
className2 obj2;
className2 obj3;
obj2 = &obj1;
obj3 = &obj2;
The above lines are executed as:
obj2.operator=(&obj1);
obj3.operator=(&obj2);
However, such coding is not intuitive. You don't assign a pointer to an object. It is more intuitive to say:
className obj1;
className* objPtr = NULL;
objPtr = &obj1;
a = &b
Here, & gives address of b.
className& operator=(const className&);
Here, operator = will take const reference of variable of type className.
You can say in C++, & is polymorphic.
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;
class item {
public:
item& operator=(const item &rh) {
...
...
return *this;
}
};
Is the following signature wrong?
void operator=(const item &rh);
item a, b;
a = b; // equivalent to a.operator=(b); so there is no need to return this.
It is not "wrong", but surprising. An assignment evaluates to the target object. That's what the builtin meaning is. If you define it different for your own class, people could become confused.
Example:
int c;
while((c = getchar()) != EOF) {
// ...
}
The assignment to c returned c itself and compared it to EOF afterwards. Users would expect your item class to behave similar.
The signature with void would not allow chained assignments:
a = b = c;
(Look at Johannes' answer for one more example of a usage pattern based on assignment returning the assigned value.)
That's why using such signatures is discouraged. However, if I am not mistaken, you actually can use such a signature.
It's perfectly legal. But when you declare operator= like that, you will be unable to make "chain of assignment":
item a(X);
item b;
item c;
c = b = a;
Reference allows modifying returned value. Since operator= is evaluated from right to left, the usage I showed to you is working.
EDIT Also, as others mentioned, return value is often used in expressions like while (a = cin.get()) != 'q'). But you also can declare operator like A operator=(const A&) (returns copy) or const A& operator(const A&) (returns const reference). My point is: this operator can return anything, but the idiomatic way is to return non-const reference to itself.