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

赋值运算符“=”要求左右两个操作数的类型是匹配的,或至少是兼容的。有时候希望赋值运算符两边的类型可以不匹配,比如,把一个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. SpringMVC配置没有任何问题根据请求却怎么都找不到映射(tomcat所导致的问题)

    本人在做SpringMVC练习的时候,配置文件反复检查了不下十几遍,没有任何问题,然后就招了个之前的项目的源码复制进去,原来的项目没有任何问题,这个项目却怎么都不能跳转路径,然后有找了一个Spring ...

  2. windows 批量杀进程 类似pkill

    轉:http://blog.sina.com.cn/s/blog_55fb522f0100whki.html 1.开始-运行(或win+R),输入cmd,打开命令行模式: 2.输入tasklist,可 ...

  3. AtCoder agc007_d Shik and Game

    洛谷题目页面传送门 & AtCoder题目页面传送门 有\(1\)根数轴,Shik初始在位置\(0\).数轴上有\(n\)只小熊,第\(i\)只在位置\(a_i\).Shik每秒可以向左移动\ ...

  4. Lesson 13 The search for oil

    What do oilmen want to achieve as soon as they strike oil? The deepest holes of all are made for oil ...

  5. 报警视图 报警窗口 报警指示器 的组态 PLC变量 事故信息 MW16 报警确认变量 MW18 转速变量 MW20 温度变量 MW22 用 M17.0 来模拟事故信息的最低位。用PLCSIM 给定温度为800 度 报警视图与报警窗口显示故障

    组态报警并用PLCSIM进行仿真 步骤1 : 组态离散变量报警 在PLC 的默认变量表中 创建变量"事故信息" 数据类型是word 绝对地址是MW16 同时建立 报警确认变量 MW ...

  6. js正则 - 限制用户名只能中文、字母和数字 , 不能包含特殊字符

    /^[\u4E00-\u9FA5A-Za-z0-9]+$/   

  7. Linux系统使用ss命令查看端口状态

    Linux系统使用ss命令查看端口状态 目录 1.可用工具 2.ss帮助 2.1 选项分类说明 2.2 过滤选项family 2.3 过滤选项state 2.4 状态之间的关系 3.ss的使用 3.1 ...

  8. 仿照Android标准API写的各种形式的弹出框

    strings.xml: <?xml version="1.0" encoding="utf-8"?> <resources> < ...

  9. Mybatis入门(五)属性名和字段名不一致解决

    在学Mybatis的时候都需要创建一个实体类,但创建实体类的变量必须和数据库的一样,这章就来解决这个有趣的问题 目录: 问题是这样: 输出的结果是: password为空,这就很难受: 解决方法: 第 ...

  10. 7.3 Varnish VCL 常用函数