理解和使用复制赋值构造函数
Understanding and using a copy assignment constructor
我想了解复制赋值构造函数在 C++ 中的工作原理。我只和 java 一起工作过,所以我真的不在我的工作范围之内。我已经阅读并看到 return 参考是一个很好的做法,但我不知道我应该怎么做。我写了这个小程序来测试这个概念:
main.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;
}
test.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;};
};
test.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=()
。我见过有人 returning *this
但从我读到的只是对对象本身的引用(在 =
的左侧),对吧?然后我考虑 returning 一个 const Test& t
对象的副本,但是这样就没有必要使用这个构造函数了吗?我要做什么 return 为什么?
I've read and seen that it's a good practice to return a reference but i don't get how i should do that.
如何
添加
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 */ }
但是然后
更重要的是,您应该避免为发布的 class 编写析构函数、复制构造函数和复制赋值运算符。编译器创建的实现足以满足 Test
.
需要返回对原始对象的引用以支持嵌套操作。
考虑
a = b = c
我们 return 来自赋值运算符的引用,因此我们可以做一些很酷的技巧,例如 。
我们要 return 引用的对象是调用运算符的对象,或 this
。所以——就像你听说过的——你会想要 return *this
.
因此您的赋值运算符可能如下所示:
Test& Test::operator=(const Test& t) {
age = t.getAge();
id = t.getID();
return *this;
}
您可能会注意到这看起来与您的 copy-constructor 惊人地相似。在更复杂的 classes 中,赋值运算符将完成 copy-constructor 的所有工作,但此外它还必须安全地删除 class 已经存储的任何值。
由于这是一个非常简单的 class,我们不需要安全删除任何内容。我们可以 re-assign 两个成员。所以这与 copy-constructor.
几乎完全相同
这意味着我们实际上可以将您的构造函数简化为仅使用运算符!
Test::Test(const Test& t) {
*this = t;
}
同样,虽然这适用于您的简单 class,但在具有更复杂 class 的生产代码中,我们通常希望为我们的构造函数使用初始化列表(阅读 here 更多):
Test::Test(const Test& t) : age(t.getAge()), id(t.getId()) { }
我想了解复制赋值构造函数在 C++ 中的工作原理。我只和 java 一起工作过,所以我真的不在我的工作范围之内。我已经阅读并看到 return 参考是一个很好的做法,但我不知道我应该怎么做。我写了这个小程序来测试这个概念:
main.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;
}
test.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;};
};
test.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=()
。我见过有人 returning *this
但从我读到的只是对对象本身的引用(在 =
的左侧),对吧?然后我考虑 returning 一个 const Test& t
对象的副本,但是这样就没有必要使用这个构造函数了吗?我要做什么 return 为什么?
I've read and seen that it's a good practice to return a reference but i don't get how i should do that.
如何
添加
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 */ }
但是然后
更重要的是,您应该避免为发布的 class 编写析构函数、复制构造函数和复制赋值运算符。编译器创建的实现足以满足 Test
.
需要返回对原始对象的引用以支持嵌套操作。 考虑
a = b = c
我们 return 来自赋值运算符的引用,因此我们可以做一些很酷的技巧,例如
我们要 return 引用的对象是调用运算符的对象,或 this
。所以——就像你听说过的——你会想要 return *this
.
因此您的赋值运算符可能如下所示:
Test& Test::operator=(const Test& t) {
age = t.getAge();
id = t.getID();
return *this;
}
您可能会注意到这看起来与您的 copy-constructor 惊人地相似。在更复杂的 classes 中,赋值运算符将完成 copy-constructor 的所有工作,但此外它还必须安全地删除 class 已经存储的任何值。
由于这是一个非常简单的 class,我们不需要安全删除任何内容。我们可以 re-assign 两个成员。所以这与 copy-constructor.
几乎完全相同这意味着我们实际上可以将您的构造函数简化为仅使用运算符!
Test::Test(const Test& t) {
*this = t;
}
同样,虽然这适用于您的简单 class,但在具有更复杂 class 的生产代码中,我们通常希望为我们的构造函数使用初始化列表(阅读 here 更多):
Test::Test(const Test& t) : age(t.getAge()), id(t.getId()) { }