1.复制控制包含的内容:复制构造函数、赋值操作符、析构函数
2.复制构造函数:
a. 定义:只有单个形参,而且该形参是对本类类型的引用,这样的构造函数被成为复制构造函数
b. 适用情况:
(1)根据一个类型的对象显示或隐式的初始化一个对象。
(2)复制一个对象,将它作为参数传给一个函数
(3)从函数返回时复制一个对象
(4)初始化顺序容器中的元素(?)
(5)根据元素初始化列表初始化数组元素(?)
3.C++中两种初始化的形式:直接初始化和复制初始化。
a.直接初始化使用=符号,而直接初始化将初始化式放在圆括号中!但当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接初始化调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象。
1 string null_book = "9-99-999-99-9"; //copy initialization 2 string dots(10,'.'); //direct initialization 3 string empty_copy = new string(); //copy initialization 4 string empty_direct; //direct initialization
b.通常直接初始化和复制初始化仅在低级别优化上存在差异。但是不支持复制的类型或使用explicit构造函数的时候,他们有本质的区别:
1 ifstream file1("filename");//ok :direct initialization 2 ifstream file2 = "filename";//error: copy constructor is private;
4.赋值操作符
a.合成赋值操作符:会执行逐个成员赋值:有操作数对象的每个成员赋值给做操作数对象的对应。除数组外,每个成员所属类型的常规方式进行赋值。对于数组,给每个数组元素赋值
b.赋值操作符的返回类型应该与内置类型赋值运算返回的类型相同。内置类型的赋值运算返回对有操作数的引用,因此,复制操作符也返回对同一类类型的应用。
1 class Sales_item{ 2 public: 3 Sales_item & operator = ( const Sales_item &); 4 }
c.复制和赋值常一起使用
5.析构函数:
a.撤销对象时会自动调用析够函数,撤销容器中的元素总是按逆序撤销。
b.许多类不许要显示析够函数,只有当有些工作需要析够函数完成时,才需要析够函数。
c.三法则:如果需要析够函数,则它也许要复制操作符和复制构造函数。
d.合成析够函数:逆序撤销每个非static成员。
6.管理指针成员的三种方法:
a.指针成员采取常规指针型行为。这样的类具有指针的所有缺陷但无需特殊的复制控制。
(1)默认复制/赋值与指针成员(注:以下HasPtr是个简单的带指针成员变量的类)
1 int obj = 0; 2 HasPtr ptr1(&obj, 42); //int * member points to obj ,val is 42 3 HasPtr PTRW(PTR1); //int * member ponts to obj,val is 42
(2)指针共享同一个对象
(3)可能出现悬垂指针
b.类可以实现所谓的“智能指针”行为。指针所指向的对象是共享的,但类能够防止悬垂指针。
1 class U_ptr { 2 friend class HasPtr; 3 int *ip; 4 size_t use; 5 U_Ptr(int *p):ip(p),use(1){} 6 ~U_Ptr(){ delete ip;} 7 }; //引入的计数器类
c.类采取值型行为。指针所指向的对象是唯一的,由每个类对象独立管理。
1 class HasPtr { 2 public: 3 HasPtr(const int &p,int i):ptr(new int(p),val(i)) {} 4 HasPtr(const HasPtr &org):ptr(new int(*org.ptr)),val(orig.val){} 5 HasPtr& operator=(const HasPtr&); 6 ~HasPtr(){ delete ptr;} 7 private: 8 int *ptr; 9 int val; 10 };