Вопрос

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;
}
Это было полезно?

Решение

The difference is that vect a = b; performs copy initialization whereas vect a; a = b; performs copy assignment. Copy initialization calls the copy constructor, whereas copy assignment calls the overloaded operator=.

In your code, your copy assignment operator copies one vector's elements over into another, which is good. However, your copy constructor simply sets baseArray of the LHS to point to the same block of memory as that of the RHS, without copying any vector elements. When two pointers point to the same memory, of course modifying one also modifies the other.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top