I'm working on my assignment in C++ course.
I have to create operator+= which will add an object to another set of object.
So, how do I implement operator+= here?
class classNew
{
anotherClass *my_objects;
public:
// TODO: classNew(int, char const *)
classNew operator+=(const anotherClass & rhs);
};
int main()
{
classNew d1(7, "w");
anotherClass sgs[5];
// somehow init sgs[0]..[4]?
for (int i=0; i<sizeof(sgs)/sizeof(*sgs); ++i)
d1 += sgs[i];
}
UPDATE:
I have something like this
newClass newClass::operator+=(const anotherClass& seg){
this->my_objs[n_seg] = seg;
return *this;
}
Unless your operator+= is intended to modify the object you're adding, which would be highly unusual, I'd suggest one two simple changes to the signature:
classNew & classNew::operator+=(const anotherClass& rhs);
You always want to return a reference to the class, otherwise you get a copy.
You have a pointer to anotherClass in your class, I assume that this is actually a pointer to an array. You simply have to copy the passed rhs to the appropriate spot in your array, reallocating it and growing it if necessary. If my assumption is incorrect, you just need to do whatever addition is defined as for your class.
If this weren't an assignment I would also suggest replacing the pointer with a std::vector<anotherClass>.
Related
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.
So for example:
const Ball& operator=(const Ball& other)
{
// Irrelevant code
return *this;
}
So I have heard that you return a reference to an object because of cascading:
Ball a,b,c;
// Unimportant initializations
a=b=c;
But why can't the method be something like:
const Ball operator=(const Ball& other)
{
// Irrelevant code
return *this;
}
Or this:
const Ball* operator=(const Ball& other)
{
// Irrelevant code
return this;
}
What if I do something like:
Ball *a, *b, *c;
// Unimportant initializations
a = b;
Would this work with both the methods I provided?
I apologize if these are dumb questions. I am still fairly new at C++.
Any help would be nice.
The return type is convention, but normally it's Ball& not const Ball&. I think you can have anything there you like (void for instance, if you don't want to return anything at all). But it's best to have something that behaves like the assignment operator does with built in types. That way people won't be surprised how your assignment operator behaves.
This code
Ball *a, *b, *c;
// Unimportant initializations
a = b;
is just pointer assignment, it will always be legal but it has nothing to do with any assignment operator you define which is for Ball objects not Ball pointers.
Returning by value would work, but you make unnecessary copies.
Returning by pointer would prevent natural chaining, you'd need some weird thing like
a = *(b = c);
And
Ball *pa;
Ball *pb;
pa = pb;
will not use your user-defined assignment operator, the assignment operator for pointers is built-in and does pointer assignment.
If you have a const reference then you cannot assign to it. If you return a pointer, again, you assign the pointer value, not the object instance.
In most cases it makes sense to stick to what is called "int semantics" whereas you make your classes behave in the same manner int does. In particular, you want cascading to work.
If you have a reference, you can chain your operations, like this
a.add(b).subtract(c);
But if you return a pointer or const, you can not do that.
You can define it this way:
const Ball operator=(const Ball& other)
{
// Irrelevant code
return *this;
}
However, you will be returning a temporary copy. The compiler will likely fix this for you when it optimizes. Additionally, chaining a = b = c when operator= takes a const Ball&, you are passing a reference to a temporary.
Returning a pointer will not work as you cannot chain, and you are dealing with different data types (pointers on the left hand side, const references on the right).
This snippet is legal:
int a;
(a = 2)++;
In one statement, we assign 2 to a and then increment a. This means that a = 2 must evaluate to a reference to a.
In order to replicate this behavior with user made types, the assignment operator needs to return a reference.
I need to implement an assignment operator for a class with a lot of members which I don't want to assign manually. Can I first make a shallow memory copy and then perform the necessary initializations?
class C
{
public:
C &operator=(const C &rhs)
{
if (&rhs == this)
return *this;
memcpy(this, &rhs, sizeof(C));
Init(rhs);
return *this;
}
.........
};
Thanks.
No. Unless the object has a POD type, this is undefined behavior. And
a user defined assignment operator means that it's not a POD. And in
practice, it could fail for a number of reasons.
One possible solution is to define a nested POD type with the data
members, and simply assign it, e.g.:
class C
{
struct Data { /* ... */ };
Data myData;
public:
C& operator=( C const& other )
{
myData = other.myData;
return *this;
}
};
Of course, that means that you need to constantly refer to each member
as myData.x, rather than simply x.
Well you could, but all your copied pointer members(if any) will then point to the same object and if that object goes out of scope, You would be left with a dangling pointer for all other objects which refer to it.
You are trying to dereference a C++ reference using the * operator. Unless you have operator* defined for this class it's not gonna work.
I mean in line
memcpy(this, *rhs, sizeof(C));
I have a class called Location and I needed to add a CArray to its member variables. This change caused the need to overload the assignment operator.
Is there a way to copy all of the variables in this class type that were being copied before I made the change and just add the additional code to copy the CArray without copying every single member variable individually?
Location& Location::operator=(const Location &rhs)
{
// Only do assignment if RHS is a different object from this.
if (this != &rhs)
{
//Copy CArray
m_LocationsToSkip.Copy(rhs.m_LocationsToSkip);
//Copy rest of member variables
//I'd prefer not to do the following
var1 = rhs.var1;
var2 = rhs.var2;
//etc
}
return *this;
}
Yes, sort of. Use a type that overloads operator= itself, so you don't have to do it in the containing class instead. Even when writing MFC code, I still mostly use std::vector, std::string, etc., instead of the MFC collection and string classes. Sometimes you're pretty much stuck using CString, but I can't recall the last time I used CArray instead of std::vector.
Yes. What I usually do is to put everything in a Members struct in the class except what is not copyable. Like this:
class Location
{
struct Members
{
int var1, var2;
};
Members m;
CArray m_LocationsToSkip;
public:
Location& operator=(Location const& rhs);
};
Location& Location::operator=(const Location &rhs)
{
// Only do assignment if RHS is a different object from this.
if (this != &rhs)
{
//Copy CArray
m_LocationsToSkip.Copy(rhs.m_LocationsToSkip);
//Copy rest of member variables
m = rhs.m; //will use Members automatically generated operator=
//which should do the correct thing because you only put
//normally copyable members in m
}
return *this;
}
I first posted about this here: https://stackoverflow.com/questions/469696/what-is-your-most-useful-c-c-utility/1609496#1609496
No you cant.
Best way to do this is use script to generate real code.
This is usually done with what's called "copy and swap idiom". You implement a copy constructor and a swap() method that exchanges member values and, most importantly, pointers to external data. With that your assignment operator looks like:
C& C::operator=( const C& c ) {
C tmp( c );
this->swap( tmp );
return *this;
}
You don't even need a self-assignment guard with this.
Based on issues growing out of previous questions: vector::erase with pointer member, Remove elements of a vector inside the loop, I still need some help on vector.erase function. I was indicated to implement a copy constructor to make the erase function work on a vector, something that is also mentioned in another question. It is essential to implement a function operator in my relevant class. On doing this I get another error on creating the copy constructor and I cannot find the reason for long. The error is “Player::Player(const Player& otherPlayer) does not provide an initiallizer for:” . What am I doing wrong? Take into consideration that Player contains as class members map, pointers and a reference (bank is a reference) . Is a simple assignment adequate for the initialization?
What should I do?
class Player
{
public:
Player(int,int,string, Bank&);
Player(const Player&);
Player& operator = (const Player& rhs);
Player::Player(const Player& otherPlayer)
{
ID = otherPlayer.ID;
pName = otherPlayer.pName;
pMoney = otherPlayer.pMoney;
doubleIndicator = otherPlayer.doubleIndicator;
position = otherPlayer.position;
bank = otherPlayer.bank;
colBought = otherPlayer.colBought;
housesColBuilt = otherPlayer.housesColBuilt;
}
Update:
I get a warning at the point of implementantion of the operator= as:"returning address of a local variable or temporary". Does this evoke a real problem? If so, how could I modify it to get over this?
Player& Player::operator=(const Player& rhs)
{
return Player(rhs);
}
In this way, I still receive a warning that the recursive function will cause stack overflow:
Player& Player::operator=(const Player& rhs)
{
*this = Player(rhs);
return *this;
}
Any hint?
You must initialize references that are members of a class with a member initializer in the constructor:
Player::Player(const Player& otherPlayer) :
bank(otherPlayer.bank)
{
//...
}
This is needed because otherwise the reference would be uninitialized, which is not allowed.
Note that the assignment bank = otherPlayer.bank; does something different: It assigns the object that is referenced, rather than sets the reference itself.
It's also good style to initialize other members (even if they aren't references) in the same way, as it can lead to more optimal code (otherwise members could be default-constructed before being assigned).