【问题标题】:Returning deep copies of objects when overloading the = operator重载 = 运算符时返回对象的深层副本
【发布时间】:2011-07-23 03:42:42
【问题描述】:

所以我为整数创建了一个容器类,并且我想重载= 运算符,以便我可以返回对象的深层副本。我的代码工作,但两个对象指向同一个地址。这是 main.cpp 文件:

int main (int argc, const char * argv[]) {
    IntList cArray(5);

    for (int i = 0; i < cArray.getLength(); i++) {
        cArray[i] = (i + 1) * 10;
    }

    using namespace std;

    for (int i = 0; i < cArray.getLength(); i++)
        cout << cArray[i] << " ";
    cout << endl << popped << endl;

    IntList cArray2(4);

    for (int i = 0; i < cArray2.getLength(); i++)
        cArray2[i] = i * 5;

    cArray2 = cArray;
    cArray2[2] = 1000;

    for (int i = 0; i < cArray.getLength(); i++)
        cout << cArray[i] << " ";
    cout << endl;
    for (int i = 0; i < cArray2.getLength(); i++)
        cout << cArray2[i] << " ";
    cout << endl;

    return 0;
}

这是IntList 类的头文件:

class IntList {
private:
    int _length;
    int* _data;

public:
    IntList(int length);
    ~IntList();

    void erase();
    void reallocate(int length);    //  Faster way to call erase() and resize()
    void resize(int length);
    void insert(int value, int index);
    void prepend(int value);
    void append(int value);
    int pop(int index);
    void removeBefore(int index);    //  Exclusive
    void removeAfter(int index);    //  Exclusive
    int getLength();
    int indexOf(int value);

    int& operator[](int index);
    IntList operator=(IntList* source);
};

这是IntClassoperator=()方法的实现:

IntList IntList::operator=(IntList* source) {
    _length = source->getLength();

    reallocate(_length);

    for (int i = 0; i < _length; i++) {
        _data[i] = (*source)[i];
    }

    return *this;
}

【问题讨论】:

  • 问题一定出在你初始化_data的方式上,但你没有向我们展示那部分。
  • @Mark, IntList::IntList(int length) : _data(new int[length]), _length(length) { }

标签: c++ arrays operator-overloading pass-by-value container-classes


【解决方案1】:

您没有使用指向 IntList 的指针 - operator= 通常采用 const &amp; 并返回对分配给的实例的引用。

IntList & IntList::operator=(IntList const & source) {
  ...
  return *this;
}

记住你还需要一个拷贝构造函数:IntList(IntList const &amp; source)

可以创建一个 operator=,它接受一个指向 IntList 的指针 - 只有在您执行以下操作时才会起作用:

IntList l1;
IntList l2;
l1 = &l2;

这不是典型用法,如果需要,您应该明确说明,例如使用void IntList::copyFrom(IntList const *) 在这种情况下。

您应该进行的其他更改:

添加这个:

int operator[](int index) const;

使这些常量:

int getLength() const;
int indexOf(int value) const;

【讨论】:

  • 查看我对马克回答的评论。
  • @Tyler:您需要将 getLength 设为 const,并添加一个 const operator[] - 请参阅更新后的答案
  • 谢谢。那行得通。我没有正确地将我的函数标记为 const。
  • +1 以获得更深入的答案并指出三法则中缺失的部分。
【解决方案2】:

您的操作员需要签名IntList&amp; operator=(const IntList&amp; source);。请注意引用而不是指针,并且您还必须通过引用返回以允许分配链接。当您在需要隐式赋值的任何地方通过指针传递它时,将使用编译器生成的浅拷贝赋值运算符。

编辑:您还需要使 getLength const 能够在赋值运算符中被调用。

【讨论】:

  • 我刚刚尝试了您的建议,我意识到我忘记将 IntList::getLength() 标记为 const。但现在 Xcode 告诉我“错误:语义问题:成员函数 'getLength' 不可行:'this' 参数的类型为 'const IntList',但函数未标记为 const”。
【解决方案3】:
IntList IntList::operator=(IntList* source) 

operator= 的签名错误,因为它的参数类型是指向IntList指针

正确的签名是这样的:

IntList & IntList::operator=(const IntList & source) //reference of source!
     //^^^ note this                      ^^^ note this as well!

也就是说,让参数类型和返回类型都引用

【讨论】:

  • 好点,但代码不会拒绝使用原始签名编译吗?
  • @Mark Ransom 旧代码完全有效,编译器很乐意为你生成一个默认的浅拷贝赋值运算符。
  • @Mark Ransom:不。在我看来,这只是另一个重载,您必须通过写 intlist2.operator=(&amp;intlist) 来明确调用它。写intlist2=intlist1 不会调用它。
【解决方案4】:

因为您的赋值运算符需要一个指向 IntList 的指针,所以您需要这样调用它:

cArray2 = &cArray;

您的示例代码使用了编译器生成的默认赋值运算符。你的赋值运算符应该有这个声明:

IntList& IntList::operator=(IntList const& source)

【讨论】:

    猜你喜欢
    • 2019-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-09
    • 2019-02-25
    • 1970-01-01
    • 2020-08-26
    • 1970-01-01
    相关资源
    最近更新 更多