C++ Primer第十三章复制控制笔记

  1. 复制构造函数、析构函数、复制控制定义
    复制构造函数: 一种特殊的构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用.当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数.当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式使用复制构造函数.
class Foo{
public:
	// 默认构造函数
	Foo();
	// 复制构造函数
	Foo(const Foo&);
}

析构函数: 构造函数的互补,当对象超出作用域或动态分配的对象被删除时,将自动应用析构函数.析构函数可用于释放对象时构造或在对象的生命期中所获取的资源.不管类是否定义了自己的析构函数,编译器都自动执行类中非static数据成员的析构函数.

复制构造函数、赋值操作符和析构函数总称为复制控制.
2. c++初始化形式:直接初始化、复制初始化
直接初始化将初始化式放在圆括号中,直接调用与实参匹配的构造函数;
复制初始化使用=符号,调用复制构造函数.复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象.

// 对于类类型对象,只有指定单个实参或显式创建一个临时对象用于复制时,才使用复制初始化.
// 首先调用接受一个C风格字符串形参的string构造函数,创建一个临时对象,然后,使用string复制构造函数将null_book初始化为那个临时对象的副本.
string null_book = "9-9999"// 复制初始化
string dots(10, '.');          // 直接初始化
string empty_copy = string();  // 复制初始化
string empty_direct;           // 直接初始化
  1. 合成的复制构造函数
    合成复制构造函数的行为时执行逐个成员初始化,将新对象初始化为原对象的副本.
    逐个成员初始化最简单的概念模式是,将合成复制构造函数看作这样一个构造函数:其中每个数据成员在构造函数初始化列表中进行初始化.
class Sales_item{
	private:
		std:string isbn;
		int units_sold;
		double revenue;
}

Sales_item::Sales_item(const Sales_item &orig):
	isbn(orig.isbn),
	units_sold(orig.units_sold),
	revenue(orig.revenue)
	{...}
  1. 合成的复制构造函数与合成的默认构造函数区别
    合成的复制构造函数是当没有定义复制构造函数时,编译器就会为我们合成一个.
    与合成的默认构造函数不同的是,即使定义了其它构造函数,也会合成复制构造函数.
  2. 复制构造函数与其它构造函数的区别
    复制构造函数与类同名,没有返回值,可以(而且应该)使用构造函数初始化列表初始化新创建对象的成员,可以在函数体中做任何其它必要工作.
  3. 禁止复制
    为了防止复制,类必须显式声明其复制构造函数为private.然后类的友元和成员仍可以进行复制,如果想要连友元和成员中的复制也禁止,就可以声明一个private复制构造函数但不对其进行定义.
    大多数类应定义复制构造函数和默认构造函数,如果定义了复制构造函数,也必须定义默认构造函数.
  4. 析构函数
    构造函数的一个用途是自动获取资源,例如,构造函数可以分配一个缓冲区或打开一个文件,在构造函数中分配了资源之后,需要一个对应操作自动回收或释放资源,析构函数便可以完成所需的资源回收,作为类构造函数的补充.
  5. 析构函数何时调用
    1)撤销类对象时自动调用析构函数
Sales_item *p = new Sales_item;
{
	// 变量(如item)在超出作用域时自动撤销,当遇到右花括号时,将运行item的析构函数
	Sales_item item(*p);
	// 动态分配对象只有在指向该对象的指针被删除时才撤销,如果没有删除指向动态对象的指针,则不会运行该对象的析构函数,对象一直存在,从而导致内存泄漏.
	// 当对象的引用或指针超出作用域时,不会运行析构函数,只有删除指向动态分配对象的指针或实际对象(而不是对象的引用)超出作用域时,才会运行析构函数
	delete p;
}

2)撤销一个容器(标准库容器或内置数组)时,也会运行容器中的类类型元素的析构函数
容器中的元素总是按逆序撤销,首先撤销下标为size()-1的元素,然后下标为size()-2,…

{
	Sales_item *p = new Sales_item[10];
	vector<Sales_item> vec(p, p+10);
	// 数组被释放,对每个元素运行析构函数
	delete []p;
}
// vec对象超出作用域,对每个元素运行析构函数
  1. 合成析构函数
    与复制构造函数或赋值操作符不同,编译器总是为我们合成一个析构函数.合成析构函数按对象创建时逆序撤销每个非static成员.因此,它按成员在类中声明次序的逆序撤销成员.对于类类型的每个成员,合成析构函数调用该成员的析构函数来撤销对象.
    合成析构函数并不删除指针成员所指向的对象.
  2. 编写析构函数
    析构函数是个成员函数,它的名字是类名字前面加上~,没有返回值,没有形参(因为没有形参,所以不能重载析构函数).
    析构函数与复制构造函数或赋值操作符之间的一个重要区别是,即使我们编写了自己的析构函数,合成析构函数依然运行.
class Sales_item{
public:
	~Sales_item(){ }
}
  1. 管理指针成员的三种方法
  1. 指针成员采用常规指针型行为,这样的类具有指针的所有缺陷但无需特殊的复制控制.
  2. 类可以实现所谓的“智能指针”行为.指针所指向的对象是共享的,但类能够防止悬垂指针.
  3. 类采用值型行为,指针所指向的对象是唯一的,由每个类对象独立管理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值