【问题标题】:Combining declaration and initialization with overloaded `=`将声明和初始化与重载的`=`结合起来
【发布时间】:2014-02-19 03:31:48
【问题描述】:

我是 C++ 新手(但对编程并不陌生——我非常了解 Java),所以这可能有一个简单的答案,我只是忽略了。

简而言之:写作和写作的区别是什么(如果有的话):

classType a = b;

写作

classType a;
a = b;

特别是当b 是函数中的引用变量并且= 被重载时?

详情/背景:

我正在开发一个自定义的 vect 类,它(最终)将保存 n 元组,其行为类似于 R^n 中的向量(即数学风格的向量,而不是 STL 风格的向量)。因此,我重载了 = 运算符以将组件从 rhs 复制到 lhs

但是,我发现,当我的 rhs 是函数中的引用变量时,组合声明/初始化使 rhs 和 lhs 引用 相同的对象 ,而单独的初始化将它们保持为不同的对象

在我下面的程序中,当我使用单行 vect a = b 时,v2 = v1 * 10 导致 v2v1 都设置为等于 v1*10,但在我编写时表现如预期vect a; a=b* 的定义中。

最小可编译示例:

我为它的长度道歉,但这是我在第一次尝试时所能得到的。我会继续寻找减少的方法。

问题出现在* 运算符的重载中。我已经评论了需要进行哪些更改才能显示该问题。

#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;
}

【问题讨论】:

  • 问题:为什么要动态分配baseArray?如果它总是 3 你不需要(你应该使用std::array&lt;double, 3&gt;。如果它的大小不同,你应该将指针存储在std::unique_ptr&lt;double&gt; 或使用std::vector&lt;double&gt;
  • @Borgleader 我想最终使它成为一个可变长度数组,但认为最好首先使用固定长度的情况(为了简单起见)。我猜测 C++ 对动态大小数组的处理与 Java 类似,但显然情况并非如此。 (tl;dr:我试图让它轻松扩展到长度为n 的数组,但似乎我还没有这样做。):)
  • 你有,但你正在做额外的工作(即:自己管理内存)。通过使用向量,您将拥有相同的功能,而无需处理内存管理。 (您也可以使用模板)。
  • @Borgleader 我想我最终可能会使用vector... 我确实考虑过模板,但我计划使用这个类,这样我在编译时并不总是知道数组的长度时间。 (我的理解是模板参数需要在编译时知道。)
  • vect result = v 调用 copy-constructor,而不是您重载的 copy-assignment 运算符。您还需要实现复制构造函数。

标签: c++ initialization operator-overloading assignment-operator


【解决方案1】:

区别在于vect a = b;执行复制初始化,而vect a; a = b;执行复制赋值。复制初始化调用复制构造函数,而复制赋值调用重载的@987654323 @。

在您的代码中,您的复制赋值运算符将一个向量的元素复制到另一个向量中,这很好。但是,您的复制构造函数只是将 LHS 的 baseArray 设置为指向与 RHS 相同的内存块,而不复制任何向量元素。当两个指针指向同一个内存时,当然修改一个也会修改另一个。

【讨论】:

    猜你喜欢
    • 2012-10-11
    • 2020-12-14
    • 1970-01-01
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多