一、重载赋值运算符“=”

赋值运算符“=”要求左右两个操作数的类型是匹配的,或至少是兼容的。有时候希望赋值运算符两边的类型可以不匹配,比如,把一个int类型变量赋值给一个Complex对象,或把一个 char * 类型的字符串赋值给一个字符串对象,此时就需要重载赋值运算符“=”。C++规定,赋值运算符“=”只能重载为成员函数。

程序示例分析:

#include<iostream>
using namespace std;
class String {
private:
char* str;
public:
String() :str(new char[]) { str[] = ; }
const char* c_str() { return str; };
String& operator = (const char* s);
String::~String() { delete[] str; }
};
String& String::operator = (const char* s)
{ //重载“=”以使得 obj = “hello”能够成立
delete[] str;
str = new char[strlen(s) + ];
strcpy(str, s);
return *this;
}
int main()
{
String s;
s = "Good Luck,"; //等价于 s.operator=("Good Luck,");
cout << s.c_str() << endl;
// String s2 = "hello!"; //这条语句要是不注释掉就会出错
s = "Shenzhou 8!"; //等价于 s.operator=("Shenzhou 8!");
cout << s.c_str() << endl;
return ;
}

输出结果:

Good Luck,
Shenzhou !

二、浅拷贝和深拷贝

同类对象之间可以通过赋值运算符“=”互相赋值。如果没有经过重载,“=”的作用就是把左边的对象的每个成员都变得和右边的对象相等,即执行逐个字节拷贝的工作,这种拷贝叫作“浅拷贝” 。

经过重载,赋值号“=”的功能不再是浅拷贝,而是将一个对象中指针成员变量指向的内容复制到另一个对象中指针成员变量指向的地方,这种拷贝叫作“深拷贝” 。

class String {
private:
char* str;
public:
String() :str(new char[]) { str[] = ; }
const char* c_str() { return str; };
String& operator = (const char* s) {
delete[] str;
str = new char[strlen(s) + ];
strcpy(str, s);
return *this;
};
~String() { delete[] str; }
};

按照这个String类的写法,下面的程序片段会引发问题

String S1, S2;
S1 = “this”;
S2 = “that”;
S1 = S2;

如不定义自己的赋值运算符,那么S1=S2实际上导致 S1.str和 S2.str指向同一地方。

如果S1对象消亡,析构函数将释放 S1.str指向的空间,则S2消亡时还要释放一次,不妥。

另外,如果执行 S1 = "other";会导致S2.str指向的地方被delete

因此要在 class String里添加成员函数:

String & operator = (const String & s) {
delete [] str;
str = new char[strlen( s.str)+];
strcpy( str,s.str);
return * this;
}

Question1:

考虑下面语句是否会有问题?

String s;
s = "Hello";
s = s;

解决办法:

解决办法:
String & operator = (const String & s){
if( this == & s)
return * this;
delete [] str;
str = new char[strlen(s.str)+];
strcpy( str,s.str);
return * this;
}

Question2:

对 operator = 返回值类型的讨论

void 好不好?

String 好不好?

为什么是 String &

对运算符进行重载的时候,好的风格是应该尽量保留运算符原本的特性

考虑

a = b = c;

(a=b)=c; //会修改a的值

分别等价于:

a.operator=(b.operator=(c));
(a.operator=(b)).operator=(c);

Question3:

上面的String类是否就没有问题了?

为 String类编写复制构造函数的时候,会面临和 = 同样的问题,用同样的方法处理。

String( String & s)
{
str = new char[strlen(s.str)+];
strcpy(str,s.str);
}

Question4:

以下说法正确的是:

A) 成员对象都是用无参构造函数初始化的

B) 封闭类中成员对象的构造函数先于封闭类的构造函数被调用

C) 封闭类中成员对象的析构函数先于封闭类的析构函数被调用

D) 若封闭类有多个成员对象,则它们的初始化顺序取决于封闭类构造函数中的成员初始化列表

《新标准C++程序设计》4.2-4.3(C++学习笔记13)的更多相关文章

  1. 《新标准C++程序设计》4.5(C++学习笔记15)

    实例:长度可变的整型数组类 int main() { //要编写可变长整型数组类,使之能如下使用: CArray a; //开始里的数组是空的 ; i < ; ++i) a.push_back( ...

  2. 《新标准C++程序设计》4.6(C++学习笔记16)

    重载流插入运算符和流提取运算符 流插入运算符:“<<” 流提取运算符:“>>” cout 是在 iostream 中定义的,ostream 类的对象. “<<” 能 ...

  3. 《新标准C++程序设计》4.4(C++学习笔记14)

    运算符重载为友元函数 一般情况下,将运算符重载为类的成员函数,是较好的选择. 但有时,重载为成员函数不能满足使用要求,重载为普通函数,又不能访问类的私有成员,所以需要将运算符重载为友元. class ...

  4. 《新标准C++程序设计》4.1(C++学习笔记12)

    运算符重载的概念和原理 一.运算符重载的需求 C++预定义的“+.-. * ./.%. ^ .&.~.!.|. = .<< >>.!= ”等运算符,只能用于基本数据类型 ...

  5. 《新标准C++程序设计》3.8(C++学习笔记10)

    友元 友元分为友元函数和友元类两种. 一.友元函数 在定义一个类的时候,可以把一些函数(包括全局函数和其它类的成员函数)声明为“友元”,这样那些函数就成为该类的友元函数,在友元函数内部就可以访问该类对 ...

  6. 《新标准C++程序设计》3.5(C++学习笔记8)

    常量对象和常量成员函数 一.常量对象 如果希望某个对象的值初始化后就再也不被改变,则定义该对象时可以在前面加const关键字,使之成为常量对象. class CDemo { private: int ...

  7. JavaScript高级程序设计(第三版)学习笔记13、14章

    第13章,事件 事件冒泡 IE的事件叫做事件冒泡:由具体到不具体 <!DOCTYPE html> <html> <head>      <title>E ...

  8. 正确处理类的复合关系------新标准c++程序设计

    假设要编写一个小区养狗管理程序,该程序需要一个“主人”类,还需要一个“狗”类.狗是有主人的,主人也有狗.假定狗只有一个主人,但一个主人可以有最多10条狗.该如何处理“主人”类和“狗”类的关系呢?下面是 ...

  9. 在成员函数中调用虚函数(关于多态的注意事项)------新标准c++程序设计

    类的成员函数之间可以互相调用.在成员函数(静态成员函数.构造函数和析构函数除外)中调用其他虚成员函数的语句是多态的.例如: #include<iostream> using namespa ...

  10. 多态实现的原理------新标准c++程序设计

    “多态”的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定.例子: #include<iostream> using namespac ...

随机推荐

  1. PTA的Python练习题(六)

    从 第3章-8 字符串逆序 开始 1. n = str(input()) n1=n[::-1] print(n1) 2. 不是很好做这道题,自己还是C语言的思维,网上几乎也找不到什么答案 s = in ...

  2. 关于热部署Devtools出现同一个类型进行类型转换失败的问题

    背景: 最近在和学长们做一个小系统,在进行任务调度的设置的时候会出现类型转换失败的错误,原本是同一个类型的,不应该出现类型转换失败的问题,起初以为是序列化的问题,回来发现并不是这个原因, 报错截图: ...

  3. 1 Struts2基本概述及其入门

    什么是Struts2? webwork+Struts1 一个基于MVC设计模式的web层框架,本质上相当于一个Servlet.. 在MVC设计模式中,Struts2作为控制器Controller来建立 ...

  4. cin和cout输⼊输出

    写再最前面:摘录于柳神的笔记:  就如同 scanf 和 printf 在 stdio.h 头⽂件中⼀样, cin 和 cout 在头⽂件 iostream ⾥⾯,看名字就知 道, io 是输⼊输出 ...

  5. Python将数据保存为txt文件的方法

    f = open('name.txt',mode='w') #打开文件,若文件不存在系统自动创建. #参数name 文件名,mode 模式. #w 只能操作写入 r 只能读取 a 向文件追加 #w+ ...

  6. Windows驱动开发-IRP超时处理

    IRP被送到底层驱动程序以后,由于硬件设备的问题,IRP不能得到及时处理,甚至有可能永远不会被处理,这时候需要对IRP超时情况进行处理,一旦在规定时间内,IRP没有被处理,操作系统就会进入到IRP的处 ...

  7. STM32L152笔记

    一 段式液晶初始化停在while(LCD_GetFlagStatus(LCD_FLAG_RDY) == RESET)中不出来,网上给的原因和解决办法: 1 也RTC的时钟有关,需要先配置RTC时钟 2 ...

  8. Dam-list

    1. Dam 2. 溃坝 3. 水坝对环境的影响 4. 水坝列表 4.1 黄河干流水电站列表 4.2 长江干流水电站列表 4.3 长江水系支流 431. 大渡河 432. 乌江 433. 雅砻江 43 ...

  9. Systemverilog for design 笔记(六)

    转载请标明出处 第一章 有限状态机建模(FSM,finite state machine) 1.1.    使用枚举类型建立状态机模型 l  三过程块建模风格:三个过程块分别实现: a.状态转换(al ...

  10. [原]JointJS流程图

    最近项目上需要用流程图来做问题定界分析,之前有同事用jsPlumb做过,但是阅读代码后觉得比较麻烦,所以自己又找了一圈,找到一个叫Dagre-D3的开源类库,画出来的效果如下图,Dagre-D3最大的 ...