《新标准C++程序设计》4.2-4.3(C++学习笔记13)
一、重载赋值运算符“=”
赋值运算符“=”要求左右两个操作数的类型是匹配的,或至少是兼容的。有时候希望赋值运算符两边的类型可以不匹配,比如,把一个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)的更多相关文章
- 《新标准C++程序设计》4.5(C++学习笔记15)
实例:长度可变的整型数组类 int main() { //要编写可变长整型数组类,使之能如下使用: CArray a; //开始里的数组是空的 ; i < ; ++i) a.push_back( ...
- 《新标准C++程序设计》4.6(C++学习笔记16)
重载流插入运算符和流提取运算符 流插入运算符:“<<” 流提取运算符:“>>” cout 是在 iostream 中定义的,ostream 类的对象. “<<” 能 ...
- 《新标准C++程序设计》4.4(C++学习笔记14)
运算符重载为友元函数 一般情况下,将运算符重载为类的成员函数,是较好的选择. 但有时,重载为成员函数不能满足使用要求,重载为普通函数,又不能访问类的私有成员,所以需要将运算符重载为友元. class ...
- 《新标准C++程序设计》4.1(C++学习笔记12)
运算符重载的概念和原理 一.运算符重载的需求 C++预定义的“+.-. * ./.%. ^ .&.~.!.|. = .<< >>.!= ”等运算符,只能用于基本数据类型 ...
- 《新标准C++程序设计》3.8(C++学习笔记10)
友元 友元分为友元函数和友元类两种. 一.友元函数 在定义一个类的时候,可以把一些函数(包括全局函数和其它类的成员函数)声明为“友元”,这样那些函数就成为该类的友元函数,在友元函数内部就可以访问该类对 ...
- 《新标准C++程序设计》3.5(C++学习笔记8)
常量对象和常量成员函数 一.常量对象 如果希望某个对象的值初始化后就再也不被改变,则定义该对象时可以在前面加const关键字,使之成为常量对象. class CDemo { private: int ...
- JavaScript高级程序设计(第三版)学习笔记13、14章
第13章,事件 事件冒泡 IE的事件叫做事件冒泡:由具体到不具体 <!DOCTYPE html> <html> <head> <title>E ...
- 正确处理类的复合关系------新标准c++程序设计
假设要编写一个小区养狗管理程序,该程序需要一个“主人”类,还需要一个“狗”类.狗是有主人的,主人也有狗.假定狗只有一个主人,但一个主人可以有最多10条狗.该如何处理“主人”类和“狗”类的关系呢?下面是 ...
- 在成员函数中调用虚函数(关于多态的注意事项)------新标准c++程序设计
类的成员函数之间可以互相调用.在成员函数(静态成员函数.构造函数和析构函数除外)中调用其他虚成员函数的语句是多态的.例如: #include<iostream> using namespa ...
- 多态实现的原理------新标准c++程序设计
“多态”的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定.例子: #include<iostream> using namespac ...
随机推荐
- centos将celery写入系统服务
第一步: 在/etc/下创建目录 celery/celery.conf 代码如下: CELERYD_NODES='w1 w2 w3' # 启动的celery进程的进程名 CELERY_BIN='/ro ...
- 如何用C++读取图片中的像素
来源:https://bbs.csdn.net/topics/391956973 3楼 #include <iostream> #include <fstream> #inc ...
- 【PAT甲级】1037 Magic Coupon (25 分)
题意: 输入一个正整数N(<=1e5),接下来输入N个整数.再输入一个正整数M(<=1e5),接下来输入M个整数.每次可以从两组数中各取一个,求最大的两个数的乘积的和. AAAAAccep ...
- Linux系统下安装python3.7.3环境
这里用到的Linux系统是centos7系统,centos7是自带py的但是py的2.7.5版本 连接服务器的使用的是SSH Secure shell 1.首先安装依赖包 1)安装gcc编译器 gcc ...
- SystemVerilog for design 笔记(二)
转载请标明出处 1. System Verilog文本值和数据类型 1.1. 增强的文本值赋值 相对于verilog,SV在文本值赋值时可以1.无需指定进制 2.赋值可以是逻辑1 用法: reg ...
- [理解] Linux 作为一个服务器是怎样的存在 (一)
长期以来我就一直有一个疑问, 为什么当我们选择使用服务器的时候都会选择 Linux 作为操作系统, 以至于只要说到服务器就会不由自主的想到Linux, 那么Linux到底是什么呢? 当然我也不会妄谈天 ...
- 126、Java面向对象之引用传递实例四,修改类成员的属性值
01.代码如下: package TIANPAN; class Message { private String info = "此内容无用"; // 定义String类型属性 p ...
- Lucene_solr
1.总结 https://pan.baidu.com/s/1pMAWk0z 密码:ekhx 2.代码 https://pan.baidu.com/s/1nxmTWy1 密码:65ec 3.资料 ...
- Python作业篇 day04
###一.写代码,有如下列表,按照要求实现每一个功能 li=['alex','bibi','cc0','didi'] #1.计算列表的长度 #2.列表中追加元素'seven',并输出添加后的列表 #3 ...
- 「Luogu P2253 好一个一中腰鼓!」
就这道题的理论难度来说绿题是有点低了,但是这道题的实际难度来看,顶多黄题,所以建议加强数据或出数据升级版. 前置芝士 线段树:具体可以看我的另一篇文章. 具体做法 暴力的方法想必都会,所以来讲一下正解 ...