I'm new to C++ (but not new to programming--I know Java pretty thoroughly), so this may have a simple answer I'm just overlooking.
Question in a nutshell: What (if anything) is the difference between writing:
classType a = b;
and writing
classType a;
a = b;
specifically when b
is a reference variable in a function and when =
is overloaded?
Details/background:
I'm working on a custom vect
class, which will (eventually) hold n-tuples that behave like vectors in R^n
(that is, math-style vectors, not STL-style vectors). As such, I've overloaded the =
operator to copy the components from rhs
to lhs
.
However, I've found that, when my rhs is a reference variable in a function, the combined declaration/initialization makes the rhs and lhs reference the same object, while the separate initialization keeps them as different objects.
In my program below, this is evidenced as v2 = v1 * 10
results in both v2
and v1
being set equal to v1*10
when I use the single-line vect a = b
, but behaves as expected when I write vect a; a=b
in the definition of *
.
Minimal Compilable Example:
I apologize for its length, but this is pared down as much as I could get it at first try. I'll keep looking for ways to reduce.
The problem occurs in the overloading of the *
operator. I've commented there as to what change is required to exhibit the problem.
#include<iostream>
#include<string.h> //For toString method
#include<sstream> //For toString method
//===================================================
// Namespace for organization
namespace linalg {
class vect {
private:
//int length;
double* baseArray;
public:
//Constructor
vect() { baseArray = new double[3]; }
//TODO: Change so edits to arrayArg do not show up in the baseArray.
vect(double arrayArg[3]) { baseArray = arrayArg; }
//Returns a string for printing
std::string toString();
//Returns the element at given index
double getElementAt(int) const;
//Operator overloading:
vect& operator=(const vect &rhs);
friend vect operator*(double num, const vect &v);
};
//===================================================
// General Methods
// elementAt : return s the given element.
double vect::getElementAt(int i) const {
return baseArray[i];
}
// toString : behaves like Java convention:
//toString : gives string representation
std::string vect::toString() {
std::string retVal;
retVal.append("[");
for (int i = 0; i < 3; i++) {
//Convert the number to a string
std::ostringstream num;
num << baseArray[i];
//Append the number to the return value
retVal.append(num.str());
//Comma separated
if (i < 3-1) retVal.append(", ");
}
retVal.append("]");
return retVal;
}
//===================================================
// Operator overloads
//Overload '=' : copies the other vector into this vector
vect& vect::operator= (const vect &rhs) {
//Check for self-assignment:
if (this == &rhs) {
return *this;
}
//Copy the rhs into this vector
for (int i = 0; i < 3; i++) {
baseArray[i] = rhs.getElementAt(i);
}
return *this;
}
//Overload scalar multiplication
vect linalg::operator*(double num, const vect &v) {
//CHANGE THIS to a single-line assignment/initialization, and the problem occurs.
vect result;
result = v;
for(int i = 0; i < 3; i++) {
result.baseArray[i] *= num;
}
return result;
}
};
using namespace linalg;
using namespace std;
int main() {
double a[3] = {2, 4, 8};
double b[3] = {5, 1, 9};
vect v1(a);
vect v2(b);
v1 = 10*v2;
cout << v1.toString() << endl;
cout << v2.toString() << endl;
system("pause"); //Pause the windows terminal
return 0;
}