高质量C++/C编程指南-第9章-类的构造函数、析构函数与赋值函数(4)

类String的赋值函数比构造函数复杂得多,分四步实现:

(1)第一步,检查自赋值。你可能会认为多此一举,难道有人会愚蠢到写出 a = a 这样的自赋值语句!的确不会。但是间接的自赋值仍有可能出现,例如

// 内容自赋值

b = a;

c = b;

a = c;
// 地址自赋值

b = &a;

a = *b;

也许有人会说:“即使出现自赋值,我也可以不理睬,大不了化点时间让对象复制自己而已,反正不会出错!”

他真的说错了。看看第二步的delete,自杀后还能复制自己吗?所以,如果发现自赋值,应该马上终止函数。注意不要将检查自赋值的if语句

if(this == &other)

错写成为

if( *this == other)

(2)第二步,用delete释放原有的内存资源。如果现在不释放,以后就没机会了,将造成内存泄露。

(3)第三步,分配新的内存资源,并复制字符串。注意函数strlen返回的是有效字符串长度,不包含结束符‘\0’。函数strcpy则连‘\0’一起复制。

(4)第四步,返回本对象的引用,目的是为了实现象 a = b = c 这样的链式表达。注意不要将 return *this 错写成 return this 。那么能否写成return other 呢?效果不是一样吗?

不可以!因为我们不知道参数other的生命期。有可能other是个临时对象,在赋值结束后它马上消失,那么return other返回的将是垃圾。

9.7 偷懒的办法处理拷贝构造函数与赋值函数
如果我们实在不想编写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的缺省函数,怎么办?

偷懒的办法是:只需将拷贝构造函数和赋值函数声明为私有函数,不用编写代码。

例如:

class A

{ …

private:

A(const A &a); // 私有的拷贝构造函数

A & operate =(const A &a); // 私有的赋值函数

};

如果有人试图编写如下程序:

A b(a); // 调用了私有的拷贝构造函数

b = a; // 调用了私有的赋值函数

编译器将指出错误,因为外界不可以操作A的私有函数。

9.8 如何在派生类中实现类的基本函数
基类的构造函数、析构函数、赋值函数都不能被派生类继承。如果类之间存在继承关系,在编写上述基本函数时应注意以下事项:

u 派生类的构造函数应在其初始化表里调用基类的构造函数。

u 基类与派生类的析构函数应该为虚(即加virtual)

时间: 2024-09-17 04:45:40

高质量C++/C编程指南-第9章-类的构造函数、析构函数与赋值函数(4)的相关文章

高质量C++/C编程指南-第10章-类的继承与组合(2)

10.2 组合l [规则10-2-1]若在逻辑上A是B的"一部分"(a part of),则不允许B从A派生,而是要用A和其它东西组合出B. 例如眼(Eye).鼻(Nose).口(Mouth).耳(Ear)是头(Head)的一部分,所以类Head应该由类Eye.Nose.Mouth.Ear组合而成,不是派生而成.如示例10-2-1所示. class Eye {public: void Look(void); };class Nose {public: void Smell(void);

高质量C++/C编程指南-第10章-类的继承与组合(1)

对象(Object)是类(Class)的一个实例(Instance).如果将对象比作房子,那么类就是房子的设计图纸.所以面向对象设计的重点是类的设计,而不是对象的设计. 对于C++程序而言,设计孤立的类是比较容易的,难的是正确设计基类及其派生类.本章仅仅论述"继承"(Inheritance)和"组合"(Composition)的概念. 注意,当前面向对象技术的应用热点是COM和CORBA,这些内容超出了C++教材的范畴,请阅读COM和CORBA相关论著. 10.1

高质量C++/C编程指南-第11章-其它编程经验(2)

11.1.3 const成员函数 任何不会修改数据成员的函数都应该声明为const类型.如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员函数,编译器将指出错误,这无疑会提高程序的健壮性. 以下程序中,类stack的成员函数GetCount仅用于计数,从逻辑上讲GetCount应当为const函数.编译器将指出GetCount函数中的错误. class Stack { public: void Push(int elem); int Pop(void); int

高质量C++/C编程指南-第7章-内存管理(1)

欢迎进入内存这片雷区.伟大的Bill Gates 曾经失言: 640K ought to be enough for everybody - Bill Gates 1981 程序员们经常编写内存管理程序,往往提心吊胆.如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的.本章的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管理. 7.1内存分配方式内存分配方式有三种: (1) 从静态存储区域分配.内存在程序编译的时候就已经分配好,这块内存在程序的整个运行

高质量C++/C编程指南-第4章-表达式和基本语句

读者可能怀疑:连if.for.while.goto.switch这样简单的东西也要探讨编程风格,是不是小题大做? 我真的发觉很多程序员用隐含错误的方式写表达式和基本语句,我自己也犯过类似的错误. 表达式和语句都属于C++/C的短语结构语法.它们看似简单,但使用时隐患比较多. 本章归纳了正确使用表达式和语句的一些规则与建议. 4.1 运算符的优先级 C++/C语言的运算符有数十个,运算符的优先级与结合律如表4-1所示.注意一元运算符 + - * 的优先级高于对应的二元运算符. 优先级 运算符 结合

高质量C++/C编程指南-第7章-内存管理(5)

7.9 内存耗尽怎么办?如果在申请动态内存时找不到足够大的内存块,malloc和new将返回NULL指针,宣告内存申请失败.通常有三种方式处理"内存耗尽"问题. (1)判断指针是否为NULL,如果是则马上用return语句终止本函数.例如: void Func(void) { A *a = new A; if(a == NULL) { return; } - } (2)判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行.例如: void Func(void) { A

高质量C++/C编程指南-第6章-函数设计(3)

对于相加函数,应当用"值传递"的方式返回String对象.如果改用"引用传递",那么函数返回值是一个指向局部对象temp的"引用".由于temp在函数结束时被自动销毁,将导致返回的"引用"无效.例如: c = a + b; 此时 a + b 并不返回期望值,c什么也得不到,流下了隐患. 6.3 函数内部实现的规则不同功能的函数其内部实现各不相同,看起来似乎无法就"内部实现"达成一致的观点.但根据经验,我们可

高质量C++/C编程指南-第11章-其它编程经验(1)

11.1 使用const提高函数的健壮性看到const关键字,C++程序员首先想到的可能是const常量.这可不是良好的条件反射.如果只知道用const定义常量,那么相当于把火药仅用于制作鞭炮.const更大的魅力是它可以修饰函数的参数.返回值,甚至函数的定义体. const是constant的缩写,"恒定不变"的意思.被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性.所以很多C++程序设计书籍建议:"Use const whenever you

高质量C++/C编程指南-第8章-C++函数的高级特性(4)

8.3 参数的缺省值有一些参数的值在每次函数调用时都相同,书写这样的语句会使人厌烦.C++语言采用参数的缺省值使书写变得简洁(在编译时,缺省值由编译器自动插入). 参数缺省值的使用规则: l [规则8-3-1]参数缺省值只能出现在函数的声明中,而不能出现在定义体中. 例如: void Foo(int x=0, int y=0); // 正确,缺省值出现在函数的声明中 void Foo(int x=0, int y=0) // 错误,缺省值出现在函数的定义体中 { - } 为什么会这样?我想是有两