转贴地址:http://blog.csdn.net/winer632/archive/2009/01/12/3762292.aspx
每个类只有一个赋值函数.
由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数有些轻视。请先记住以下的警告,在阅读正文时就会多心:
1.如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。以类String的两个对象a,b为例,假设a.m_data的内容为“hello”,b.m_data的内容为“world”。
现将a赋给b,缺省赋值函数的“位拷贝”意味着执行b.m_data = a.m_data。这将造成三个错误:一是b.m_data原有的内存没被释放,造成内存泄露;二是b.m_data和a.m_data指向同一块内存,a或b任何一方变动都会影响另一方;三是在对象被析构时,m_data被释放了两次。
2.拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。以下程序中,第三个语句和第四个语句很相似,你分得清楚哪个调用了拷贝构造函数,哪个调用了赋值函数吗?
String a(“hello”);
String b(“world”);
String c = a; // 调用了拷贝构造函数,最好写成 c(a);
c = b; // 调用了赋值函数
本例中第三个语句的风格较差,宜改写成String c(a) 以区别于第四个语句。
类String的拷贝构造函数与赋值函数
// 拷贝构造函数
String::String(const String &other)
{
// 允许操作other的私有成员m_data
int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data, other.m_data);
}
// 赋值函数
String & String::operate =(const String &other)
{
// (1) 检查自赋值
if(this == &other)
return *this;
// (2) 释放原有的内存资源
delete [] m_data;
// (3)分配新的内存资源,并复制内容
int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data, other.m_data);
// (4)返回本对象的引用
return *this;
}
类String拷贝构造函数与普通构造函数的区别是:在函数入口处无需与NULL进行比较,这是因为“引用”不可能是NULL,而“指针”可以为NULL。
类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返回的将是垃圾。
偷懒的办法处理拷贝构造函数与赋值函数
如果我们实在不想编写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的缺省函数,怎么办?
偷懒的办法是:只需将拷贝构造函数和赋值函数声明为私有函数,不用编写代码。
例如:
class A
{ …
private:
A(const A &a); // 私有的拷贝构造函数
A & operate =(const A &a); // 私有的赋值函数
};
如果有人试图编写如下程序:
A b(a); // 调用了私有的拷贝构造函数
b = a; // 调用了私有的赋值函数
编译器将指出错误,因为外界不可以操作A的私有函数。
3.在编写派生类的赋值函数时,注意不要忘记对基类的数据成员重新赋值.
分享到:
相关推荐
编写该类的构造函数、拷贝构造函数和析构函数,在构造函数和拷贝构造函数中动态申请内存空间赋值给m_data。用于存储字符串。在析构函数中释放内存空间。 ⑵ 重载运算符“+”作为类MyString的成员函数,使能完成字符...
10.5 拷贝构造函数和赋值函数 10.6 多态的概念 10.7 友元 1章 继承与接口 11.1 覆盖 11.2 私有继承 11.3 虚函数继承和虚继承 11.4 多重继承 11.5 检测并修改不适合的继承 11.6 纯虚函数 11.7 ...
第10章 引用和拷贝构造函数 10.1C++中的指针 10.2C+十中的引用 10.2.1函数中的引用 10.2.2参数传递准则 10.3拷贝构造函数 10.3.1传值方式传递和返回 10.3.2拷贝构造函数 10.3.3缺省拷贝构造函数 10.3.4拷贝构造...
按以下描述和要求建立两个类:基类 Rectangle(矩形类...(4) 调用 add 函数,将 B 和 C 的高度值之和赋值给 D 的高度值,输出 D 的全部数据,计 算并输出 D 的体积。 文件为word形式,请复制粘贴到VS的cpp文件中运行。
条款11: 为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符 条款12: 尽量使用初始化而不要在构造函数里赋值 条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同 条款14: 确定基类有虚析构...
为了避免这样的警告,C++允许声明一个无名形参,以告诉编译器存在该参数,且调用者需要为其传递一个实际参数,但是函数不会用到这个参数。下面给出使用了无名参数的C++函数代码: int fun(int x,int) //注意不同点...
4、编写拷贝构造函数和重载赋值运算符,完成字符串类对象直接赋值操作。 5、编写析构函数,释放初始化时开辟的空间。 6、编写求字符串长度函数,不允许使用strlen或类似功能函数。 7、编写字符串拷贝函数,不允许...
设计模式思想是可重用,我们在编程的过程中,或多或少都会接触到设计模式,只是,有时,我们相交却未相识罢了,那么我们来讲解单例模式... a、拷贝构造函数声明为私有,并且不提供实现 b、将赋值运算符声明为私有
条款11:为需要动态分配内存的类声明一个拷贝构造函数和一个赋值函数 条款12:尽量使用初始化而不要在构造函数里赋值 条款13:初始化列表中成员列出顺序和它们在类中的声明顺序相同 条款14:确定基类有虚析构函数 条款15...
(7) 在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。 在虚继承体系中的通过virtual继承而来的基类 继承子类与父类关系 具体化 类的层次通常...
目录GIL锁GIL定义:GIL介绍GIL与LockGIL与多线程Python 直接赋值、浅拷贝、深拷贝私有属性魔法方法属性访问控制描述符对像构造自定义容器上下文管理对象的序列化运算符相关的魔术方法比较运算符一元运算符和函数算术...
二进制是基数为2,每位的权是以2 为底的幂的进制,遵循逢二进一原则,基本符号为0和1。采用二进制码表示信息,有如下几个优点:1.易于物理实现;2.二进制数运算简单;3.机器可靠性高;4.通用性强。其缺点是它表示数...
定义该类的构造 ,拷贝构造,析构函数。为该类重载运算符+,-(友元函数),前置和后置++,-- (成员函数),插入符和提取符,>>(友元函数)。在main函数里定义复数对象,测 试重载的这些运算符。 2.进阶部分 (2)...
上面就是一个类的声明,从属性和方法上声明出来的一个类,但是成员属性最好在声明的时候 不要给初始的值,因为我们做的人这个类是一个描述信息,将来用它实例化对象,比如实例化出来 10 个人对象,那么这10 个人, ...
面试题11:谈谈对拷贝构造函数和赋值运算符的认识 面试题12:写出当定义#define _INMAIN 0和不定义时代码打印结果 第9章 继承与多态 9.1 继承 面试题1:指出程序的错误 面试题2:用C++设计一个不能被继承的类 9.2 虚...
2.1 构造函数 2.2 赋值 2.3 公用数据 2.4 隐式类型转换 2.5 操作符重载:成员或非成员? 2.6 重载、缺省值以及省略符 2.7 Const 2.8 返回值为引用 2.9 静态对象的构造 2.10 小结 2.11 问题 第3章 句柄 3.1 一个...
//拷贝构造函数 ~ String(void);// 析构函数 String & operate =(const String &other);// 赋值函数 private: char* m_data;// 用于保存字符串 }; 请编写String的上述4个函数。 标准答案: // String的析构函数 ...
6.20 *拷贝python对象、浅拷贝和深拷贝 6.21 序列类型小结 6.22 练习 第7章 映像和集合类型 7.1 映射类型:字典 7.1.1 如何创建字典和给字典赋值 7.1.2 如何访问字典中的值 ...
6.20 *拷贝python对象、浅拷贝和深拷贝 6.21 序列类型小结 6.22 练习 第7章 映像和集合类型 7.1 映射类型:字典 7.1.1 如何创建字典和给字典赋值 7.1.2 如何访问字典中的值 ...