第十三章:复制控制

1.      

复制构造函数是一种特殊的构造函数,具有单个形参(常用const来修饰)是该类类型的引用.当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数.当将该类型的对象传递给函数返回该类型的对象时,将隐式使用复制构造函数.

2.      不管是否定义了自己的析构函数,编译器都自动执行类中非static数据成员的析构函数

3.      复制构造函数可用于:

●根据另一个同类型的对象显示或者隐式初始化一个对象

●复制一个对象,将它作为实参传递给一个函数

●初始化顺序容器中的元素

●根据元素初始化式列表初始化数组元素

4.如果我们没有定义复制构造函数,编译器就会为我们合成一个.与合成的默认构造函数不同,即使我们定义了其他构造函数,也会合成复制构造函数.合成复制构造函数的行为是,执行逐个成员初始化,将新对象初始化为原对象的副本.

        所谓逐个成员指的是编译器将现有对象的每个非static成员,一次复制到正创建的对象.只有数组复制是个例外.如果类具有数组成员,则合成复制构造函数将复制数组.复制数组时合成复制构造函数将复制数组的每一个元素.

        逐个成员初始化最简单的概念模型是,将合成复制构造函数看做成这样的构造函数:其中每个数据成员在构造函数初始化列表中进行初始化.

5.下面两种情况必须定义复制构造函数:

        ●有些类必须对复制对象时发生的事情加以控制;这样的类经常有一个数据成员是指针.或者有成员表示在构造函数中分配的其他资源.

        ●某些类在创建新对象时必须做一些特定工作

        定义复制构造函数名与类同名,无返回值,可以(而且应该使用构造函数初始化列表初始化新创建的成员,可以在函数体中做任何其他必要的工作.

6.为了防止复制,类必须显示声明其复构造函数为private,如果想要连友元和成员中的复制也禁止,就可以声明一个复制构造函数但不对其定义.

        大多数类应定义复制构造函数和默认构造函数,如果定义了复制构造函数,也必须定义默认构造函数.

7.赋值操作符接受单个形参,且该形参是同一类型的对象.右操作数一般作为const引用传递.

(2011-12-30加上)而且赋值操作符返回的类型一般都是左操作数类型的的引用.(书上说内置内型是返回右操作数的引用.我觉得不对,而且它给出的例子也是返回左操作数的引用)

举例:

struct A
{

string strName;

int     iID;

A& operator=(constA& a )

{

strName = a.strName;

iID= a.iID;

return *this;

}

};

8.当对象的引用或者超出作用域时,不会运行析构函数.只有删除指向动态分配对象的指针或者实际对象(而不是对象的引用)超出作用域时,才会运行析构函数.并且元素总是逆序撤销

        通常类需要析构函数,则它也需要赋值操作符和复制构造函数.这是一个有用的经验法则

        与复制构造函数或者赋值操作符不同的是,编译器总是会为我们合成一个析构函数

9.析构函数与复制构造函数或者赋值操作符之间的一个重要区别是:即使我们编写了自己的析构函数,合成析构函数仍然运行.

10.编写自己的复制构造函数时,必须显式复制需要复制的任意成员.显式定义复制构造函数不会进行任何自动复制

11.即使对象赋值给自己,赋值操作符的正确工作也非常重要.保证这个行为的通用方法是显示检查对自身的赋值.赋值操作符通常要做复制构造函数和析构函数也要完成的工作.在这种情况下,通用工作应放在private使用函数中.

(2011-12-30 通常如果我们需要定义析构函数,那么我们也应该定义复制构造函数与赋值操作符)

如果想要测试构造函数的调用情况.我们可以使用下面类似的方法来查看.

#include <iostream>
#include <string>

using std::string;
using namespace std;
class A
{
private:
	string strName;
	int     iID;
public:
	A()
	{
		cout<<"A的构造函数运行...\n";
	}

	A& operator=( const A& a );
	A( const A& a )
	{
		cout<<"A的复制函数正在运行...\n";
	}
};
A& A::operator=( const A& a )
{
	cout<<"A的赋值操作符运行..\n";
	strName = a.strName;
	iID		= a.iID;
	return *this;
}
void main()
{
	A a;
//	A b = a;
	a =b;

	system( "pause" );
	return;
}

运行结果如下:

12.包含指针的类需要特别注意复制控制,原因是赋值指针时只是复制指针中的地址,而不会赋值指针指向的对象

13.大多数C++类采用以下三种方法之一管理指针成员:

        ●指针成员采取常规指针型行为.这样的类具有指针的所有缺陷但无需特殊的复制控制

●类可以实现所谓的智能指针行为,指针所指向的对象是共享的,但类能防止垂悬指针

●类采取值型行为.指针所指向的对象是唯一的,有每个类对象独立管理

具有指针成员且使用默认合成复制构造函数的类具有普通指针的所有缺陷.尤其是,类本身无法避免垂悬指针.

14.引入智能指针时使用计数,将一个计数器与类指向的对象相关联(这类似于COM技术中的引用计数技术).复制构造函数复制指针并增加与之相应的使用技术.对一个对象进行赋值时,赋值操作符减少左操作数所指向的使用计数的值(如果减少至0,则删除对象),并增加右操作数所指对象的引用计数的值.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值