I have the following class which is called CoordinatesList. It contains a dynamic array of Coordinates, where each coordinate has 3 integers; x,y, and z.
In the class CoordinatesList, I have two different member operator=, I am slightly confused about what is the difference between them?
Will it work the same if I inherited the class coordinates in the class CoordinatesList
class Coordinates {//this is a complete class, do not modify it.
public:
Coordinates() {
x = new int; y = new int; z = new int;
*x = *z = *y = 0;
}
Coordinates(int _x, int _y, int _z) {
x = new int; y = new int; z = new int;
*x = _x;
*z = _y;
*y = _z;
}
Coordinates(const Coordinates& rhs) { // copy constructor
x = new int; y = new int; z = new int;
*x = *(rhs.x);
*y = *(rhs.y);
*z = *(rhs.z);
}
~Coordinates() {
delete x; delete y; delete z;
}
void operator=(const Coordinates& rhs) {//simplified operator=
*x = *(rhs.x);
*y = *(rhs.y);
*z = *(rhs.z);
}
int getx() const { return *x; }
int gety() const { return *y; }
int getz() const { return *z; }
void setx(int _x) { *x = _x; }
void sety(int _y) { *y = _y; }
void setz(int _z) { *z = _z; }
friend ostream& operator<< (ostream& out, const Coordinates& rhs) {
out << "[" << *(rhs.x) << "," << *(rhs.y) << "," << *(rhs.z) << "]" << endl;
return out;
}
private:
int *x, *y, *z;
}; //--------------------------------------------------------------
class CoordinatesList {
public:
/*CoordinatesList & operator=(const CoordinatesList &rhs)
{
if (size != rhs.size)
{
delete[] list;
size = rhs.size;
list = new Coordinates[size];
}
for (int i = 0; i < size; i++)
{
list[i].Coordinates::operator=(rhs.list[i]);
}
return *this;
} */
CoordinatesList operator=(const CoordinatesList & rhs)
{
//check if sizes are differernt
if (size != rhs.size)
{
delete[] list; //this calls ~coordinates
size = rhs.size;
list = new Coordinates[size];
}
//copy content
for (int i = 0; i < size; i++) {
//list[i] = rhs.list[i];
//will work as operator= is defined for Coordinates
list[i].setx(rhs.list[i].getx());
list[i].sety(rhs.list[i].gety());
list[i].setz(rhs.list[i].getz());
}
return *this;
}
private:
Coordinates * list;
int size;
};
using CL = CoordinatesList; to save on typing.
The difference is that one returns a reference, one returns a copy.
The idiomatic way is to return a reference to *this, so use this one:
CL& operator=(const CL& rhs){/*...*/ return *this;}
Note that having both versions defined will result in a compiler error because functions cannot differ only by their return values.
Usage of operator=:
CL a = CL(<args>);// (1)
CL b,c;
b = a; // (2)
b.operator=(a); //(3)
c = b = a; // (4)
c.operator=(b.operator=(a)); // (5)
(1) Does not call any CL::operator= but a constructor CL::CL(<args>). An object is being created, so a constructor must be called no matter the equal sign.
(2) Is only syntactic sugar for (3). Calls CL::operator= and discards any returned value.
(4) Again, its only syntactic sugar for (5). First the right operator= is evaluated and the returned value is passed to the left operator= as its argument. In this case having operator= returning a copy will indeed make a copy. That's the reason why the second option is preferred as it does not incur this additional and unneeded cost. Also this should be a good explanation for why the function returns anything at all, if it returned void then this syntax would not be possible.
Related
The code given is:
#include<iostream>
using namespace std;
class Test{
private:
int x;
int y;
public:
Test (int x = 0, int y = 0) { this->x = x; this->y = y; }
Test setX(int a) {
x = a;
return *this;
}
Test setY(int b) {
y = b;
return *this;
}
void print() {
cout << "x = " << x << " y = " << y << endl;
}
};
Basically I was returning a user-defined object from a member function of the same class.
Test obj1;
obj1.setX(10).setY(24);
obj1.print();
When cpp obj1.setX(10) was executed, was the returned object an lvalue or an rvalue?
If I use the above code, it gives the output as x = 10 y = 0. This got me thinking, is the user-defined object an rvalue or an lvalue, because in the case of primitive data-types (where the function returns a primitive data types) the returned value is an rvalue.
Also, I want to further add that I get the desired output i.e. x = 10 y = 24 if I write,
Test& setX(int a) {
x = a;
return *this;
}
Test& setY(int b) {
y = b;
return *this;
}
Please explain this too.
code looks like this
#include<iostream>
class A
{
public:
int* a;
char name;
A(char _n = 'N')
{
a = 0;
name = _n;
}
A(int _a, int _b, char _n = 'N')
{
name = _n;
a = new int[2]{ _a, _b };
}
~A()
{
std::cout << "deleting object..." << name << "\n";
delete[] a;
}
//
void operator=(A b)
{
std::cout << "cleanup begin\n";
delete[] a;
a = new int[] {b.a[0], b.a[1]};
}
//
A Copy()
{
if (a == 0) return *new A();
A* _r = new A(a[0], a[1], name + 1);
return *_r;
}
};
//
int main()
{
A d{0, 1, 'T'};
{
A Z(0, 1);
Z = Z.Copy();
}
std::cout << "check\n";
return 0;
}
I want Z = Z.Copy() to work but instead it triggers a breakpoint in delete_scalar.
From what i understand, the overloaded = should free the memory that is allocated to member a, after which it should allocate new memory and copy the integers by value, then destroying b.
Even so, object Z from the nameless scope has its destructor called twice, leading to the breakpoint trigger.
All that I want is to be able to do something like this:
x = (x - y) * z + y;
where I can overload = for x to assign to it the result of overloaded object operations (x and y are custom vector3 instances, z is a custom Matrix4 instance, Matrix4 contains a float*, if that's relevant).
So, what is the problem and how do I solve it?
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have the following code :
class FLOAT
{
float *num;
public:
FLOAT(){}
FLOAT(float f)
{
num = new float(f);
}
FLOAT operator +(FLOAT& obj)
{
FLOAT temp;
temp.num = new float;
temp.num = *num + obj.getF();
return temp;
}
float getF(){ return *num; }
void showF(){ cout << "num : "<< *num << endl; }
};
It is showing an error.
My question is, how do I access that float *num data member using class object?
There are a lot of mistakes in your class. It is simply not setup correctly.
The class's default constructor is not allocating the float at all.
the class is not following the Rule of 3/5/0. It is missing a destructor to free the float, a copy constructor and copy assignment operator to make safe copies of the float, and in C++11 and later, it is missing a move constructor and move assignment operator to safely move the float between objects.
your operator+ is not dereferencing the pointer when assigning a new value to the float.
Try this instead:
class FLOAT
{
float *num;
public:
FLOAT(float f = 0) : num(new float(f)) {}
FLOAT(const FLOAT &src) : num(new float(*(src.num))) {}
// in C++11 and later...
FLOAT(FLOAT &&src) : num(src.num) { src.num = nullptr; }
// alternatively:
// FLOAT(FLOAT &&src) : num(nullptr) { std::swap(num, src.num); }
~FLOAT() { delete num; }
FLOAT& operator=(const FLOAT &rhs)
{
*num = *(rhs.num);
return *this;
}
// in C++11 and later...
FLOAT& operator=(FLOAT &&rhs)
{
std::swap(num, rhs.num);
return *this;
}
FLOAT operator+(const FLOAT& rhs)
{
FLOAT temp;
*(temp.num) = *num + rhs.getF();
return temp;
// or simply:
// return *num + rhs.getF();
}
float getF() const { return *num; }
void showF() { cout << "num : " << *num << endl; }
};
That being said, there is no good reason to dynamically allocate the float at all (except maybe as a learning experience). Let the compiler handle the memory management for you:
class FLOAT
{
float num;
public:
FLOAT(float f = 0) : num(f) {}
FLOAT(const FLOAT &src) : num(src.num) {}
FLOAT& operator=(const FLOAT &rhs)
{
num = rhs.num;
return *this;
}
FLOAT operator+(const FLOAT& rhs)
{
FLOAT temp;
temp.num = num + rhs.getF();
return temp;
// or simply:
// return num + rhs.getF();
}
float getF() const { return num; }
void showF() { cout << "num : " << num << endl; }
};
Which can then be simplified a little by letting the compiler implicitly define the copy constructor and copy assignment operator for you:
class FLOAT
{
float num;
public:
FLOAT(float f = 0) : num(f) {}
FLOAT operator+(const FLOAT& rhs)
{
FLOAT temp;
temp.num = num + rhs.getF();
return temp;
// or simply:
// return num + rhs.getF();
}
float getF() const { return num; }
void showF() { cout << "num : " << num << endl; }
};
When you assign bellow statement :
temp.num = *num + obj.getF();
Actually you assign a float number to a float pointer!
So, use of bellow :
(*temp.num) = (*num) + obj.getF();
Instead of :
temp.num = *num + obj.getF();
The MWE is
#include <iostream>
using namespace std;
class N {
public:
float x;
N() { x = 0.0; }
N(float a) { x = a; }
//N(N &n) { x = n.x; }
N &operator=(float f) { cout << "########";return *new N(f); }
};
int main() {
N a;
a = 3.0;
cout << a.x;
return 0;
}
What I expect is: it prints 3, but it actually prints 0. It seems the value didn't change.
Then I change it into
x = f; return *this;
It worked, why?
Of course it doesn't change. You don't change it in your assignment operator. Instead you return a pointer to a new value allocated on the heap...and ignore that result.
#include<iostream>
using namespace std;
class Test
{
private:
int x;
int y;
public:
Test (int x = 0, int y = 0) { this->x = x; this->y = y; }
Test setX(int a) { x = a; return *this; }
Test setY(int b) { y = b; return *this; }
void print() { cout << "x = " << x << " y = " << y << endl; }
};
int main()
{
Test obj1;
obj1.setX(10).setY(20);
obj1.print();
return 0;
}
In this program, if I use the chaining functions, values of x and y it comes to be : x=10, y=0 instead of x=10 , y=20
If instead of chaining function, I use:
obj1.setX(10) and obj1.setY(20) separately,
x value comes to be 10
y value comes to 20.
Can someone please explain why it is like this.
Your set* methods are returning copies of the Test object.
So when you chain your calls, the setY is applied to the temporary copy, and thrown away.
You can either return a reference on an object:
Test &setX(int a) { x = a; return *this; }
Test &setY(int b) { x = b; return *this; }
Or to store copy of changed object:
Test obj1;
Test objCopy = obj1.setX(10).setY(20);
objCopy.print();
First is more efficient due to not copying object.