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

赋值运算符“=”要求左右两个操作数的类型是匹配的,或至少是兼容的。有时候希望赋值运算符两边的类型可以不匹配,比如,把一个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. 基于Modelsim的视频流仿真

    一.前言 最近在看牟新刚写的<基于FPGA的数字图像处理原理及应用>,书中关于FPGA数字图像处理的原理的原理写的非常透彻,在网上寻找了很久都没有找到完整的源代码工程,因此尝试自己做了补充 ...

  2. 树莓派4B踩坑指南 - (3)无显示器连接

    无显示器连接 WiFi:如果是原装系统,直接修改wpa_supplicant.conf文件后,放入boot即可(一定注意ssid名称不要写错!!惨痛教训T^T) SSH:在boot盘下新建一个 SSH ...

  3. CDC学习

    最近在建立CDC环境,在网上看到一些不错的学习链接,粘贴如下: 1.https://blog.csdn.net/u011729865/article/details/52931366 属于https: ...

  4. Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application

    在广播中启动一个Dialog时出现如下错误信息:Caused by: android.view.WindowManager$BadTokenException: Unable to add windo ...

  5. 58按之字形顺序打印二叉树 +队列访问使用front和back,栈才是top

    题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推.   思路:最暴力的方法就是使用队列进行层次遍 ...

  6. 「CF1004E」Sonya and Ice Cream

    题目描述 给定一个 \(N\) 个点的树,要选出一条所含点的个数不超过 \(K\) 的一条路径,使得路径外的点到这条路径的距离的最大值最小. 数据范围:\(1\le K \le N \le 10^5\ ...

  7. SSM 返回静态页面HTML Controller 被递归调用引起的StackOverflowError

    一 背景 最近在做工程实践,想实现这么一个效果: 前端url请求地址:localhost:8080/idevtools/search 后端返回一个静态页面HTML:search.html 按照网上说的 ...

  8. 单表千亿电信大数据场景,使用Spark+CarbonData替换Impala案例

    [背景介绍] 国内某移动局点使用Impala组件处理电信业务详单,每天处理约100TB左右详单,详单表记录每天大于百亿级别,在使用impala过程中存在以下问题: 详单采用Parquet格式存储,数据 ...

  9. Eclipse配置maven和新建maven工程

    1 安装配置Maven 1.1 下载Maven 从Apache网站 http://maven.apache.org/ 下载并且解压缩安装Apache Maven.  Maven下载地址: http:/ ...

  10. session存取时 getOutputStream()和getWriter()问题

    情况1: 在使用httpResponse的getWriter()会写json是出现 getWriter() has already been called for this response,经我查看 ...