effective c++条款11扩展——关于拷贝构造函数和赋值运算符
作者:冯明德

重点:包含动态分配成员的类 应提供拷贝构造函数,并重载"="赋值操作符。

以下讨论中将用到的例子:

class CExample
{
public:
CExample(){pBuffer=NULL; nSize=0;}
~CExample(){delete pBuffer;}
void Init(int n){ pBuffer=new char[n]; nSize=n;}
private:
char *pBuffer; //类的对象中包含指针,指向动态分配的内存资源
int nSize;
};

这个类的主要特点是包含指向其他资源的指针。

pBuffer指向堆中分配的一段内存空间。

一、拷贝构造函数

int main(int argc, char* argv[])
{
CExample theObjone;
theObjone.Init40);
//现在需要另一个对象,需要将他初始化称对象一的状态
CExample theObjtwo=theObjone;
...
}

语句"CExample theObjtwo=theObjone;"用theObjone初始化theObjtwo。

其完成方式是内存拷贝,复制所有成员的值。

完成后,theObjtwo.pBuffer==theObjone.pBuffer。

即它们将指向同样的地方,指针虽然复制了,但所指向的空间并没有复制,而是由两个对象共用了。这样不符合要求,对象之间不独立了,并为空间的删除带来隐患。

所以需要采用必要的手段来避免此类情况。

回顾以下此语句的具体过程:首先建立对象theObjtwo,并调用其构造函数,然后成员被拷贝。

可以在构造函数中添加操作来解决指针成员的问题。

所以C++语法中除了提供缺省形式的构造函数外,还规范了另一种特殊的构造函数:拷贝构造函数,上面的语句中,如果类中定义了拷贝构造函数,这对象建立时,调用的将是拷贝构造函数,在拷贝构造函数中,可以根据传入的变量,复制指针所指向的资源。

拷贝构造函数的格式为:构造函数名(对象的引用)

提供了拷贝构造函数后的CExample类定义为:

class CExample
{
public:
CExample(){pBuffer=NULL; nSize=0;}
~CExample(){delete pBuffer;}
CExample(const CExample&); //拷贝构造函数
void Init(int n){ pBuffer=new char[n]; nSize=n;}
private:
char *pBuffer; //类的对象中包含指针,指向动态分配的内存资源
int nSize;
};
CExample::CExample(const CExample& RightSides) //拷贝构造函数的定义
{
nSize=RightSides.nSize; //复制常规成员
pBuffer=new char[nSize]; //复制指针指向的内容
memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char));
}

这样,定义新对象,并用已有对象初始化新对象时,CExample(const CExample& RightSides)将被调用,而已有对象用别名RightSides传给构造函数,以用来作复制。

原则上,应该为所有包含动态分配成员的类都提供拷贝构造函数。

拷贝构造函数的另一种调用。

当对象直接作为参数传给函数时,函数将建立对象的临时拷贝,这个拷贝过程也将调同拷贝构造函数。

例如

BOOL testfunc(CExample obj);
testfunc(theObjone); //对象直接作为参数。
BOOL testfunc(CExample obj)
{
//针对obj的操作实际上是针对复制后的临时拷贝进行的
}

还有一种情况,也是与临时对象有关的

当函数中的局部对象被被返回给函数调者时,也将建立此局部对象的一个临时拷贝,拷贝构造函数也将被调用

CTest func()
{
CTest theTest;
return theTest
}

二、赋值符的重载

下面的代码与上例相似

int main(int argc, char* argv[])
{
CExample theObjone;
theObjone.Init(40);
CExample theObjthree;
theObjthree.Init(60);
//现在需要一个对象赋值操作,被赋值对象的原内容被清除,并用右边对象的内容填充。
theObjthree=theObjone;
return 0;
}

也用到了"="号,但与"一、"中的例子并不同,"一、"的例子中,"="在对象声明语句中,表示初始化。更多时候,这种初始化也可用括号表示。

例如 CExample theObjone(theObjtwo);

而本例子中,"="表示赋值操作。将对象theObjone的内容复制到对象theObjthree;,这其中涉及到对象theObjthree原有内容的丢弃,新内容的复制。

但"="的缺省操作只是将成员变量的值相应复制。旧的值被自然丢弃。

由于对象内包含指针,将造成不良后果:指针的值被丢弃了,但指针指向的内容并未释放。指针的值被复制了,但指针所指内容并未复制。

因此,包含动态分配成员的类除提供拷贝构造函数外,还应该考虑重载"="赋值操作符号。

类定义变为:

class CExample
{
...
CExample(const CExample&); //拷贝构造函数
CExample& operator = (const CExample&); //赋值符重载
...
};
//赋值操作符重载
CExample & CExample::operator = (const CExample& RightSides)
{
nSize=RightSides.nSize; //复制常规成员
char *temp=new char[nSize]; //复制指针指向的内容
memcpy(temp,RightSides.pBuffer,nSize*sizeof(char));
delete []pBuffer; //删除原指针指向内容  (将删除操作放在后面,避免X=X特殊情况下,内容的丢失)
pBuffer=temp;   //建立新指向
return *this
}

三、拷贝构造函数使用赋值运算符重载的代码。

CExample::CExample(const CExample& RightSides)
{
pBuffer=NULL;
*this=RightSides    //调用重载后的"="
}

posted on 2008-06-04 15:04 GXW 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/Fancyboy2004/archive/2008/06/04/1213510.html

effective c++条款11扩展——关于拷贝构造函数和赋值运算符相关推荐

  1. 浅谈深浅拷贝问题(这里只针对拷贝构造函数和赋值运算符重载)和简易srting类模拟实现

    浅谈深浅拷贝问题(这里只针对拷贝构造函数和赋值运算符重载)和简易srting类模拟实现 文章目录 浅谈深浅拷贝问题(这里只针对拷贝构造函数和赋值运算符重载)和简易srting类模拟实现 一.什么是浅拷 ...

  2. C++编程思想:指针,引用,拷贝构造函数,赋值运算符

    文章目录 对指针的引用和指针的指针到底是怎么一回事? 函数返回引用到底返回了什么? 拷贝构造函数和默认拷贝构造函数 自定义拷贝构造函数 使用默认拷贝构造函数 =赋值运算符重载 对指针的引用和指针的指针 ...

  3. C++ 拷贝构造函数和赋值运算符

    本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义 ...

  4. 运算符重载——拷贝构造函数与赋值运算符的区别、如何实现赋值运算符的深拷贝

    目录: 运算符重载--算术运算符重载 运算符重载--递增运算符重载 运算符重载--左移运算符重载 运算符重载--赋值运算符重载 写在前面 1)C++的编译器会默认给一个类提供4个函数 默认构造函数(无 ...

  5. 【C++ Primer 第15章】定义派生类拷贝构造函数、赋值运算符

    学习资料 • 派生类的赋值运算符/赋值构造函数也必须处理它的基类成员的赋值 • C++ 基类构造函数带参数的继承方式及派生类的初始化 定义拷贝构造函数 [注意]对派生类进行拷贝构造时,如果想让基类的成 ...

  6. C++ 一个例子彻底搞清楚拷贝构造函数和赋值运算符重载的区别

    class TestChild { public:TestChild(){x=0;y=0;printf("TestChild: Constructor be called!\n") ...

  7. Effective C++ 条款11:在operator=中处理自我赋值

    "自我赋值"发生在对象被赋值给自己时: class Widget { ... }; Widget w; ... w = w; // 赋值给自己 a[i] = a[j]; // 潜在 ...

  8. effective C++ 条款 11:在operator= 处理‘自我赋值’

    假设建立一个class来保存一个指针指向一块儿动态分配的位图(bitmap) class Bitmap{...}; class Widget { public: protected: private: ...

  9. 拷贝构造函数和赋值函数的一些知识

    /*******************拷贝构造函数和赋值运算符重载有以下两个不同之处***************************/ 1.拷贝构造函数生成新的类对象,而赋值运算符不能. 2. ...

最新文章

  1. FD.io/VPP — VNF 应用场景
  2. CMake常见指令总结
  3. OpenCV 加载图像、转换图像和保存图像
  4. boot返回码规范 spring_sprigboot-new-coding-standards
  5. macos中xcode使用opencv,错误总结
  6. PHP和MySQL Web开发从新手到高手,第1天-搭建PHP开发环境
  7. 2016-08-12
  8. Android NDK: 如何编译JNI为指定的指令集(armeabi/arm64)
  9. 黑苹果声卡、显卡、网卡驱动教程
  10. Web全栈~02.表单样式设计
  11. 阿里云主体变更和备案过程
  12. vue 父组件与子组件直接的相互传值(愚见)
  13. OpenAI gym Atari游戏的环境设置
  14. win10 64位系统上注册wincc的ocx插件问题
  15. b B KB MB GB TB 之间的关系与换算
  16. vue中reject与provide使用
  17. 图灵 数理逻辑 人工智能 图灵机与计算问题 论文
  18. LeetCode 题库 全 JAVA 解题---771.宝石与石头
  19. 计算机学研究生课程,厦门大学计算机学系研究生课程.doc
  20. 微信小游戏一笔画通关代码---------深度优先图搜问题

热门文章

  1. PHP 实现快速排序
  2. VS 添加文件添加文件成链接
  3. 前端性能优化之图像优化原理
  4. ERP CRM与SCM整合过程中的知识转移
  5. 视频图像不正常的几个表现及解决方法
  6. [summary] 单调队列
  7. 超赞!12套你没见过的社交媒体 社交网站图标
  8. USB主机是如何检测到设备的插入的呢?
  9. CCIR601和CCIR656标准的区别
  10. 如何实现ABB机器人与老式焊机的连接控制