C++: Parent object change their id attribute without method call - c++

As I specified in the title, this is a problem that puzzled me enormously, and still I can not find a fix for it.
I created a Point class which has three private attributes (_id, _x and _y) with related public get and set methods.
For example, I created three points (G, H, R), where the point G is a "parent". Point H is the prototype of the point G (a clone) and point R will be the outcome of the meeting points (G+H) (addition of the points).
Points sample:
Point G ("pG", 3.5f, 6.5f);
Point H (G.prototype ()); H.setId ("pH");
Point R;
R = G + H;
The program works correctly, but unfortunately after the operation {R=G+H}, _id attribute of point G becomes the clone attribute of point R, I do not understand why this is happening because the evaluation is done from right to left (H+, +G, =R).
The question is why G point attribute changes itself?
Code where the problem occurs:
#include <iostream>
#include <string>
using namespace std;
class Point
{
private:
string _id;
double _x;
double _y;
public:
Point(string id="undefined", double x = 0.00f, double y = 0.00f)
:_id(id), _x(x), _y(y){}
~Point(){}
public:
// Getters methods
string getId() const { return _id;}
double getX() const { return _x; }
double getY() const { return _y; }
void setId(string id) { _id = id; }
// Setters methods
void setX(double n = 0.00f) { _x = n; }
void setY(double n = 0.00f) { _y = n; }
Point prototype() { return Point(_id, _x, _y); }
Point operator+ (const Point& p)
{
cout << "Operator + called, returning a new object" << endl;
return Point
(
_id.append("+").append(p._id),
_x+p._x,
_y+p._y
);
}
Point operator= (const Point& p)
{
cout << "Operator = called, returning a new object Point(p._id, p._x, p._y)" << endl;
_id=p._id;
_x=p._x;
_y=p._y;
return *this;
}
};
int main()
{
Point G("G",10.0f, 10.0f);
Point H(G.prototype()); H.setId("H");
Point R;
R = G + H;
cout << "object Point {id: " << G.getId() << ", x: " << G.getX() << ", y: " << G.getY() << "}" << endl;
cout << "object Point {id: " << H.getId() << ", x: " << H.getX() << ", y: " << H.getY() << "}" << endl;
cout << "object Point {id: " << R.getId() << ", x: " << R.getX() << ", y: " << R.getY() << "}" << endl;
return 0;
}
Thanks in advance!

Point operator+ (const Point& p)
{
cout << "Operator + called, returning a new object" << endl;
return Point
(
_id.append("+").append(p._id), // HERE
_x+p._x,
_y+p._y
);
}
In this line, you modify _id property of this object. As a rule of thumb, binary + operator should be a const member or - IMO cleaner - a static method taking two const reference arguments.
BTW, you can add strings in C++ by just applying + operator to them (_id + "+" + p._id).

If you implement your binary arithmetic operators as members, you should consider making the operator a const member. This would catch the obvious modification in your implementation (the implementation is made out of line to avoid including unrelated code):
Point Point::operator+ (const Point& p) const
{
cout << "Operator + called, returning a new object" << endl;
return Point
(
_id.append("+").append(p._id),
_x+p._x,
_y+p._y
);
}
The operation _id.append("+") actually operates on this->_id, i.e., the _id member of the left hand operand. Since you member operator isn't const, the compiler lets you do the modification. This is probably not what you intended to do. You probably rather wanted to write:
Point Point::operator+ (const Point& p) const
{
cout << "Operator + called, returning a new object\n";
return Point
(
_id + "+" + p._id,
_x+p._x,
_y+p._y
);
}
... which creates a suitable temporary string with the desired value (I also replaced the excessive use of std::endl).

This line in the operator+ overload:
_id.append("+").append(p._id),
You have to be very careful here, you are currently in an object (in your example this would be the G object). append actually alters the local string, so your code is appending + then p._id then deep copying that to the returned value.
A quick fix is to change this to a temporary that holds what you need:
_id + "+" + p._id
To avoid problems like this in the future, you should declare operator overloads as a friend method so it's extremely clear what you're operating on.
friend Point operator+ (const Point& lhs, const Point& rhs)
{
cout << "Operator + called, returning a new object" << endl;
return Point
(
lhs._id.append("+").append(rhs._id), //COMPILER ERROR! We're modifying the const "lhs"!
lhs._x+rhs._x,
lhs._y+rhs._y
);
}
So let's change this to:
friend Point operator+ (const Point& lhs, const Point& rhs)
{
cout << "Operator + called, returning a new object" << endl;
return Point
(
lhs._id + "+" + rhs._id, // no longer modifying lhs -- all is well!
lhs._x+rhs._x,
lhs._y+rhs._y
);
}

Related

Assignment operator overloading: returning void versus returning reference parameter [duplicate]

This question already has answers here:
Why should the assignment operator return a reference to the object?
(4 answers)
Closed 6 years ago.
Some of the assignment overloading operator examples I see online look like this:
#include <iostream>
using namespace std;
class Distance {
private:
int feet; // 0 to infinite
int inches; // 0 to 12
public:
// required constructors
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
void operator = (const Distance &D ) {
cout << "assigning..." << endl;
feet = D.feet;
inches = D.inches;
}
// method to display distance
void displayDistance() {
cout << "F: " << feet << " I:" << inches << endl;
}
};
int main() {
Distance D1(11, 10), D2(5, 11);
cout << "First Distance : ";
D1.displayDistance();
cout << "Second Distance :";
D2.displayDistance();
// use assignment operator
D1 = D2;
cout << "First Distance :";
D1.displayDistance();
return 0;
}
They return void from the overloaded function. This makes sense to me if D1 is the object being called.
Other examples return a reference to a class object.
#include <iostream>
using namespace std;
class Distance {
private:
int feet; // 0 to infinite
int inches; // 0 to 12
public:
// required constructors
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
Distance& operator = (const Distance &D ) {
cout << "assigning..." << endl;
feet = D.feet;
inches = D.inches;
return *this;
}
// method to display distance
void displayDistance() {
cout << "F: " << feet << " I:" << inches << endl;
}
};
int main() {
Distance D1(11, 10), D2(5, 11);
cout << "First Distance : ";
D1.displayDistance();
cout << "Second Distance :";
D2.displayDistance();
// use assignment operator
D1 = D2;
cout << "First Distance :";
D1.displayDistance();
return 0;
}
This does not make sense to me (when taking the first example into consideration). If in the first example D1 = D2; invokes something like D1.=(D2);, why would the second example work in that case? Is it something like D1 = D1.=(D2);? And does it make any difference at the end of the day?
Although C++ language lets you overload assignment operator with any return type, including void, you should strongly consider following a widespread convention of returning a reference to the assignee from the operator.
The rationale for it is that
A = B;
will work no matter what the assignment returns, while
A = B = C;
which is a perfect chain of assignments will break, unless B = C returns something assignment-compatible to A (which is usually an object of the same type as A).
Another problem is in situations when you must compare the object as part of a larger expression, for example
mytype obj;
while ((obj = read_obj(cin)) != END_OBJ) {
...
}
Hence, the biggest drawback to returning void is inability to chain assignments and use them in places where void is not allowed.
As a convention, assignment operator usually returns reference (to *this); which makes it possible to chain the assignment, just like the behavior of those built-in types. e.g.
Distance D1, D2, D3;
D1 = D2 = D3;
For D1 = D2;, it's equivalent with D1.operator=(D2);. It doesn't change for the 2nd case, the returned value is just discarded. For D1 = D2 = D3;, it's equivalent with D1.operator=(D2.operator=(D3));. Note the returned value (i.e. reference to D2) is used as the argument for the assignment operator called on D1.

Object with same address but different values [duplicate]

This question already has answers here:
Returning a reference to a local variable in C++
(3 answers)
Closed 6 years ago.
I'm trying to build a class complex,
and in the method conjugate I want the return statement to return the same object as the local variable res and not a copy of it.
#include <iostream>
#include <math.h>
using namespace std;
class complex
{
float x, y;
public:
complex(float x, float y);
complex(float x) :complex(x, 0){}
complex() :complex(0, 0){}
complex(const complex &z) : complex(z.x, z.y) {}
~complex();
complex &conjugate();
friend ostream& operator<<(ostream&, const complex&);
};
ostream& operator<<(ostream& out, const complex& z){
out << z.x << "+" << z.y << "i";
return out;
}
complex::complex(float x, float y){
cout << "complex number created.\n";
this->x = x;
this->y = y;
}
complex &complex::conjugate(){
complex res;
res.x = this->x;
res.y = -this->y;
cout << "res val: " << res << endl;
cout << "res addr: " << &res << endl;
return res;
}
int main(){
complex a(1, 2);
complex* c = &(a.conjugate());
cout << "c val= " << *c << endl;
cout << "c addr= " << c << endl;
getchar();
return 0;
}
Output:
complex number created.
complex number created.
res val: 1+-2i
res addr: 002CFA0C
c val: -1.07374e+008+-1.07374e+008i
c addr: 002CFA0C
*c and the local variable res have the same address but not the same value.
Could anyone explain to me why?
res disappears after conjugate returns. You made what is called a dangling reference/pointer which is an error in the program. After you call conjugate again it makes a new variable res that happens to have the same address, but not the same value.
To solve this issue you can make res a static variable (static complex res;) so its lifetime persists past the end of the function.
You are returning a reference to a local variable that is about to be destroyed at the end of the function scope. That will not end well. Basically, the reference is useless since it refers to a destroyed object and using it is undefined - anything could happen, the code is broken.

Copy constructor invoked 2 times, not 3 as expected?

Here is one program taken from a textbook featuring copy constructors:
#include <stdio.h>
#include <conio.h>
#include <iostream>
using namespace std;
class point
{
private:
int x,y;
public:
point(int ox =0, int oy =0)
{
cout << " Make object" << this << endl;
cout << " Using default constructor \n";
x = ox, y = oy;
}
point(const point &p)
{
cout << " Make object" << this << endl;
cout << " Using copy constructor \n";
x = p.x, y = p.y;
}
void move(int dx, int dy);
void display();
};
point fct(point a);
int main()
{
point a(5,2);
a.display();
point b = fct (a);
b.display();
getch();
return 0;
}
void point::move(int dx, int dy)
{
x += dx, y += dy;
}
void point::display()
{
cout << "Coordinates :" << x << " " << y << "\n";
}
point fct(point a)
{
point b=a;
//b.move(2,3);
return b;
}
It should be noted that the copy constructor is of the form : point (const point &p) instead of point (point &p) (the latter is what's in the textbook, but couldn't compile so I had to switch to the first one, but still I can't understand why :( )
The textbook said that there will be 3 lines of "Using copy constructor" , corresponding to 3 calls to the copy constructor. I think the reason for that is, when you call: b = fct(a)
The function "fct" makes a copy of a (pass-by-value), therefor one call
The line : point b = a : again, a copy constructor is invoked
The return value is then copied into b (the variable in main, not the one in fct) this is 3rd one.
However upon execution, there is only 2 calls. Can anyone give me a good explaination on this?
Two copies occur because Named Return Value Optimization (NRVO) elides one of the copies.
point fct(point a)
{
point b=a;
return b;
}
point b = fct (a);
The first copy is the one from the argument a in main to the parameter a in fct. This occurs because the point is taken by-value.
The second copy is from a to b inside func.
The copy which is elided is the one in returning b by value. In this case, b can be directly allocated into the b at the call site, so no copy takes place.

Operator Overloading = Negation not working as intended

So I'm working with operator overloading and just realized that my negation operator isn't working as it should be. I'm not exactly sure what I've done wrong.
The .h signature
Vector & Vector::operator-()
The .cpp implementation
Vector & Vector::operator-()
{
pVec[0] = -pVec[0];
pVec[1] = -pVec[1];
pVec[2] = -pVec[2];
return *this;
};
Calling:
cout << "-Vector E = " << -VecE << (-VecE).Magnitude() << endl << endl;
The variables in VecE are like [0, 1 , 1] which means when this is called it should display them as [0, -1, -1] but it's not. So what am I missing?
EDIT: Adding copy constructor and iostream<< overload code:
Vector::Vector(const Vector & Copy)
{
pVec = new double[3];
if (0 == pVec)
{
exit(1);
}
else
{
pVec[0] = Copy.pVec[0];
pVec[1] = Copy.pVec[1];
pVec[2] = Copy.pVec[2];
}
};
ostream & operator<<(ostream & Out, Vector & RHS)
{
cout.precision(1);
Out << fixed << "[ " << RHS.pVec[0] << " " << RHS.pVec[1] << " " << RHS.pVec[2] << " ]" << resetiosflags (ios_base::fixed);
return Out;
};
You need to return a copy of the vector. The way this is written, the expression -VecE will actually modify VecE! Since you evaluate -VecE twice, you are negating the vector twice, and (of course) the negation of the negation is the original value.
To implement this change, you need to alter the operator-() declaration to return a Vector instead of a Vector &.
For example:
Vector Vector::operator-()
{
Vector copy(*this);
copy.pVec[0] = -copy.pVec[0];
copy.pVec[1] = -copy.pVec[1];
copy.pVec[2] = -copy.pVec[2];
return copy;
};
cdhowie is right. You are negating twice.
That said, I don't think you need to change the implementation.
Vector const NegVecE = -VecE;
cout << "-Vector E = " << NegVecE << NegVecE.Magnitude() << endl << endl;
EDIT: As PiotrNycz notes, though this will work, the end state is un-intuitive and therefore the correct solution is to return a copy.
{
int i = 3;
int j = -i; //you would expect i to still be 3 here
}

Overloading the subscript operator "[ ]" in the l-value and r-value cases

I have overloaded [] operator in my class Interval to return minutes or seconds.
But I am not sure how to assign values to minutes or second using [] operator.
For example : I can use this statement
cout << a[1] << "min and " << a[0] << "sec" << endl;
but I want to overload [] operator, so that I can even assign values to minutes or seconds using
a[1] = 5;
a[0] = 10;
My code :
#include <iostream>
using namespace std;
class Interval
{
public:
long minutes;
long seconds;
Interval(long m, long s)
{
minutes = m + s / 60;
seconds = s % 60;
}
void Print() const
{
cout << minutes << ':' << seconds << endl;
}
long operator[](int index) const
{
if(index == 0)
return seconds;
return minutes;
}
};
int main(void)
{
Interval a(5, 75);
a.Print();
cout << endl;
cout << a[1] << "min and " << a[0] << "sec" << endl;
cout << endl;
}
I know I have to declare member variables as private, but I have declared here as public just for my convenience.
Return a reference to the member in question, instead of its value:
long &operator[](int index)
{
if (index == 0)
return seconds;
else
return minutes;
}
Change the function signature by removing the const and returning a reference:
long& operator[](int index)
Now you will be able to write statements like:
a[0] = 12;
Overloading op[] to use hardcoded "index" values doesn't make sense here, and you actually already have the solution in your class definition:
cout << a.minutes << "min and " << a.seconds << "sec" << endl;
You can turn those into methods instead of public data members, that's inconsequential for not overloading op[]. However, since you want write access as well, the only advantage a method would have is validation (e.g. checking 0 <= seconds < 60).
struct Interval {
int minutes() const { return _minutes; }
void minutes(int n) { _minutes = n; } // allows negative values, etc.
int seconds() const { return _seconds; }
void seconds(int n) {
if (0 <= n and n < 60) {
_seconds = n;
}
else {
throw std::logic_error("invalid seconds value");
}
}
// rest of class definition much like you have it
private:
int _minutes, _seconds;
};
// ...
cout << a.minutes() << "min and " << a.seconds() << "sec" << endl;
return by reference to be able to assign values and use them on the LHS of the assignment operator.
converting the method to as given below should do it:
long& operator[](int index)
Your array index member operator should be provided as
long& operator[](int index); // for non const object expressions
long const& operator[](int index) const; // for const object expressions
In-order to avoid confusion in the case of overloading the sub-script operator, it is recommended to use the const and non-const version of the sub-script operator.
long& operator[](int index); // non-const function returning reference
long const& operator[](int index) const;// const function returning const reference
With A[1] = 5, you are trying to modify the object at index 1. So the non-const version of the sub-script operator will be invoked automatically.
With cout << A[1], you are not modifying the object at index 1. So the const version of the sub-script operator will be invoked automatically.