You are on page 1of 6

拷贝赋值运算符是一种在C++中常用的运算符,用于将一个对象的值赋给另一个

对象。它的语法形式为:

class_name& operator=(const class_name& other);

在这个运算符中,类名代表要赋值的对象类型,等号表示赋值操作,const关键字表示参
数是一个常量,class_name&表示返回一个指向类对象的引用,other表示要拷贝的对象。
拷贝赋值运算符的作用是将一个对象的所有成员变量的值复制到另一个对象中,实
现两个对象的值的相等。它通常在对象的赋值语句中使用,比如:

ClassA obj1;
ClassA obj2;
obj2 = obj1; // 使用拷贝赋值运算符将obj1的值赋给obj2

但是,如果类中存在指针成员变量,简单的拷贝赋值运算符可能会导致浅拷贝,即两
个对象的指针成员变量指向同一个内存地址,这会造成潜在的问题。为了避免这种
情况,我们需要自定义拷贝赋值运算符,实现深拷贝,即复制指针指向的内容而不是
指针本身。
如果您正在寻找一家专业的写作服务公司,我们推荐您使用HelpWriting.net。这是一家
拥有多年经验的专业写作团队,拥有高素质的写作人员和严格的质量控制流程,能够
为您提供高质量的作业、论文、报告等各种写作服务。无论您是需要拷贝赋值运算符
相关的作业帮助,还是其他学术写作服务,HelpWriting.net都能满足您的需求。
通过HelpWriting.net,您可以轻松获得优质的作业帮助,节省宝贵的时间,同时还能享
受到专业的写作指导和贴心的客服服务。不要再为作业烦恼,立即访问HelpWriting.net
,让我们为您提供最好的写作服务!
private: } } private: int A::s_assign_count = 0; _year = d._year; // 全局的operator== _second =
t._second; ~MyString() std::cout << s.c_str() << std::endl; std::cout << s1.c_str() << std::endl;
MyString & operator=(const MyString & s) } // 这里需要注意的是,左操作数是this,指向调
用函数的对象 return *this; return 0; // 返回该对象 Date d2(d1); b = a; // 赋值运算符无
疑 DataType* _array; class A }; { Time() {
所以综上考虑,operator= 返回值类型是MyString &是比较好的。 s2 = "Hi~"; // 等价
于s2.operator=("Hi~"); int _hour; int _hour; }; // 构造函数,默认初始化1个字节的字
符 private: return m_str; } 例如上图的width=80.5,就是将80.5赋值给width变量,此时widht
的值是80.5。 临时对象a并非直接构造再返回,而是构造以后,还执行了一些额外的逻
辑。测试结果也是一样的,也就是说,只要返回一个对象,那么开启优化后,编译器一
般都是直接在返回对象上构造,而不会构造临时对象后再拷贝构造。这样的具名对
象返回值优化称作NRVO (Named Return Value Optimization) 。 static int s_copy_count; { bool
operator==(const Date& d1, const Date& d2) { } 如果使用默认的复制(拷贝)构造函数,那
就对有指针成员变量的对象会有问题,因为会默认的复制(拷贝)构造函数会导致两
个对象的指针成员变量指向同一个的空间。 _size = 0; { 自动传递 { { _size = 0; void
Push(const DataType& data) // 全局的operator== s1 = "this"; // 调用重载的赋值语句 }
// 拷贝新字符串的内容 _month = month; { MyString & operator= (const char *s) void Test() {
int _second; MyString & operator= (const char *s) 会调用构造函数的msvc的debug版汇编翻
译就会变成调用移动构造函数,其他版本还是会优化成直接构造。 这时当一个对象
释放了指针成员变量时,那么另外一个对象的指针成员变量指向的地址就是空
的了,再次使用这个对象时,程序就会奔溃了,因为该对象的指针成员函数已经是个
不合法的指针了! }; return 0; if (this != &t) { MyString & operator=(const MyString & s) 从字
面上看, 应该是先构造一个临时对象,然后再拷贝构造调用者申请的对象。只有msvc
的debug版的汇编代码是这样翻译,msvc的release 版以及gcc的debug 、release 版都是直接
对调用者接收对象调用构造函数。所以我们设计的类,直接构造或者先构造再拷贝
构造的的效果必须是一致、无副作用。否则代码的行为可能会因编译选项不同而导
致行为不一样。前面的测试代码主要目的在于演示,它内部的统计构造、拷贝次数,
以及打印的内容,构造和构造再拷贝构造的结果是不一致的。 A(int value){} ~Stack() {
public: 例如下面的代码创建了变量a,并赋值为30,然后使用print函数输出变量a的
内容。 Test(d1); 长方形的面积公式a?b就是一个代数式,字母a表示长方形的长,字母b表
示长方形的宽,当确定了长方形的长和宽时,a和b表示的数就确定了,代数式的计算
结果也就确定了。 printf("A Copy\r\n");
printf("A Destruct\r\n"); } class Date private: size_t _size; 最后两条语句的结果是: class
MyString // 字符串类 _day = d._day; return *this; printf("A move\r\n"); s = s;等价
于s.operator=(s),由于s和s是相同的对象,那么就没必要完全执行重载的赋值 = 的函
数了,我们再加个判断,当左右两边是相同对象时,就直接返回该对象就好: // 构造函
数 } size_t _capacity; } int _day; class Date return 0; A d = A(a); // 拷贝构造,还是赋值运算,
还是先拷贝构造再赋值运算? _second = 1; { }; return *this; { _minute = 1; 从字面上看,
应该是先构造一个临时对象,然后再拷贝构造调用者申请的对象。只有msvc的debug版
的汇编代码是这样翻译,msvc的release版以及gcc的debug、release版都是直接对调用者接
收对象调用构造函数。所以我们设计的类,直接构造或者先构造再拷贝构造的的效
果必须是一致、无副作用。否则代码的行为可能会因编译选项不同而导致行为不
一样。前面的测试代码主要目的在于演示,它内部的统计构造、拷贝次数,以及打印
的内容,构造和构造再拷贝构造的结果是不一致的。需要注意的一点是:上面的
MyString s2 = "Hello!";语句实际上是初始化语句,而不是赋值语句,因为是初始化
语句,所以需要调用构造函数进行初始化,那么这时就需要有char*参数的构造函数,
由于我们没有定义此构造函数,所以就会编译出错。
size_t _capacity; 赋值运算符除了“=” 赋值运算符外,还有复合赋值运算符,复合赋值运
算符是赋值运算符和算术运算符合并成一个新的运算符,该运算符称为复合赋值运
算符。使用复合赋值运算符时,被赋值的变量首先使用算术运算符与右侧的数值或
算术表达式进行运算,然后将运算结果再赋值给变量。 return *this; // 释放旧字符串资
源 return *this; A(int value){} // 拷贝构造函数(Copy constructor) (4)变量的名称要有意义,
尽量做到见名知意。见名知意的意思就是我看到变量名称,就知道这个变量表示的
是什么意义。 { { s_assign_count++; // 拷贝新字符串的内容 }; int _hour; } int _year; A(A&
rhs){} //不带const也合法 } return 0; _size = 0; private: size_t _capacity; } private:

You might also like