3

我试图了解复制赋值构造函数在 C++ 中是如何工作的。我只使用过java,所以我真的不在我的水域。我已经阅读并看到返回参考是一个很好的做法,但我不明白我应该如何做到这一点。我写了这个小程序来测试这个概念:

主.cpp:

#include <iostream>
#include "test.h"

using namespace std;

int main() {
    Test t1,t2;
    t1.setAge(10);
    t1.setId('a');
    t2.setAge(20);
    t2.setId('b');

    cout << "T2 (before) : " << t2.getAge() << t2.getID() << "\n";

    t2 = t1; // calls assignment operator, same as t2.operator=(t1)

    cout << "T2 (assignment operator called) : " << t2.getAge() << t2.getID() << "\n";

    Test t3 = t1; // copy constr, same as Test t3(t1)

    cout << "T3 (copy constructor using T1) : " << t3.getAge() << t3.getID() << "\n";

    return 1;
}

测试.h:

class Test {
    int age;
    char id;

    public:
        Test(){};
        Test(const Test& t); // copy
        Test& operator=(const Test& obj); // copy assign
        ~Test();
        void setAge(int a);
        void setId(char i);
        int getAge() const {return age;};
        char getID() const {return id;};
};

测试.cpp:

#include "test.h"

void Test::setAge(int a) {
    age = a;
}

void Test::setId(char i) {
    id = i;
}

Test::Test(const Test& t) {
    age = t.getAge();
    id = t.getID();
}

Test& Test::operator=(const Test& t) {

}

Test::~Test() {};

我似乎无法理解我应该在里面放什么operator=()。我见过人们回来*this,但从我读到的只是对对象本身的引用(在左侧=),对吧?然后我考虑返回const Test& t对象的副本,但是使用这个构造函数没有意义吗?我要返回什么,为什么?

4

3 回答 3

5

我已经阅读并看到返回参考是一个很好的做法,但我不明白我应该如何做到这一点。

如何

添加

return *this;

作为函数的最后一行。

Test& Test::operator=(const Test& t) {
   ...
   return *this;
}

为什么

至于为什么要 return 的问题*this,答案是惯用的。

对于基本类型,您可以使用以下内容:

int i;
i = 10;
i = someFunction();

您可以在链操作中使用它们。

int j = i = someFunction();

您可以在条件中使用它们。

if ( (i = someFunction()) != 0 ) { /* Do something */ }

您可以在函数调用中使用它们。

foo((i = someFunction());

它们之所以起作用,是因为i = ...评估对i. 即使对于用户定义的类型,保持这种语义也是惯用的。您应该能够使用:

Test a;
Test b;

b = a = someFunctionThatReturnsTest();

if ( (a = omeFunctionThatReturnsTest()).getAge() > 20 ) { /* Do something */ }

但是之后

更重要的是,您应该避免为发布的类编写析构函数、复制构造函数和复制赋值运算符。编译器创建的实现对于Test.

于 2019-06-07T21:14:53.150 回答
2

需要返回对原始对象的引用以支持嵌套操作。考虑

a = b = c
于 2019-06-07T21:18:06.173 回答
2

我们从赋值运算符返回一个引用,这样我们就可以做一些很酷的技巧,比如@SomeWittyUsername 显示

我们要返回引用的对象是正在调用操作符的对象,或者this. 所以——就像你听说的那样——你会想回来*this的。

所以你的赋值运算符可能看起来像:

Test& Test::operator=(const Test& t) {
    age = t.getAge();
    id = t.getID();
    return *this;
}

您可能会注意到这看起来与您的复制构造函数非常相似。在更复杂的类中,赋值运算符将完成复制构造函数的所有工作,但除此之外,它还必须安全地删除该类已经存储的任何值。

由于这是一个非常简单的类,我们不需要安全删除任何内容。我们可以重新分配两个成员。所以这将与复制构造函数几乎完全相同。

这意味着我们实际上可以将您的构造函数简化为只使用运算符!

Test::Test(const Test& t) {
    *this = t;
}

同样,虽然这适用于您的简单类,但在具有更复杂类的生产代码中,我们通常希望为我们的构造函数使用初始化列表(阅读此处了解更多信息):

Test::Test(const Test& t) : age(t.getAge()), id(t.getId()) { }
于 2019-06-07T21:29:55.160 回答