13.1
拷贝构造函数是什么?什么时候使用它?
符合 “ 第一个参数是自身类类型的引用,且任何额外参数都有默认值 ” 的 构造函数 是拷贝构造函数。
当:
1.将一个对象作为实参传递给一个非引用类型的形参 (调用实参作为非&参数)
2.从一个返回类型为非引用类型的函数返回一个对象 (f(x)返回非&类型)
3.用花括号列表初始化一个数组中的元素或者一个聚合类中的成员 (列表初始化一个array或者聚合类成员)时。
13.2
解释为什么下面的声明是非法的:
Sales_data::Sales_data(Sales_data rhs);
拷贝构造函数的第一个参数应该是自身类类型的引用,如果不是,则调用永远不可能成功——为了调用拷贝构造函数,我们必须拷贝它的实参,但为了拷贝实参,我们又需要调用拷贝构造函数,如此无限循环。
13.3
当我们拷贝一个StrBlob时,会发生什么?拷贝一个StrBlobPtr呢?
StrBlob中元素复制,且智能指针计数加一。StrBlobStr中元素复制,弱指针复制不影响计数器
13.4
假定Point是一个类类型,他有一个Public的拷贝构造函数,指出下面程序片段中哪些地方使用了拷贝构造函数:
Point global;
Point foo_bar(Point arg)
{
Point local = arg,*heap = new Point(global);
*heap = local;
Point pa[4] = (local,*heap);
return *heap;
}
foo_bar 的参数不是引用类型,需拷贝;使用拷贝构造函数,函数返回类型非引用,需拷贝;将arg拷贝到local、将global拷贝到heap,将local和*heap拷贝pa[4],需拷贝;local拷贝到*heap属于拷贝赋值运算符。
13.5
给定下面的类框架,编写一个拷贝构造函数,拷贝所有成员。你的构造函数应该动态分配一个新的string(参见12.1.2节,第407页),并将对象拷贝到ps指向的位置,而不是拷贝ps本身:
class HasPtr{
public:
HasPtr(const std::string &s = std::string()):
ps(new std::string(s)),i(0) {}
private:
std::string:: *ps;
int i;
}
HasPtr(const Hasptr& HP):ps(new string (*HP.ps)),i(HP.i){}
13.6
拷贝赋值运算符是什么?什么时候使用它?合成拷贝赋值运算符完成什么工作?什么时候会生成合成拷贝赋值运算符?
就是一个名为 operator= 的函数(operator后加表示要定义的运算符的符号),重载运算符,有返回类型和参数,返回类型通常是左侧运算符的引用;
若在类内未显式定义,则编译器会自动生成合成拷贝赋值运算符,它主要是将运算符右侧的所有非static成员赋给左侧元算对象对应成员(或是用来禁止该类型对象的赋值)
13.7
当我们将一个StrBlob赋值给另一个StrBlob时,会发生什么?赋值StrBlobPtr呢?
所有成员的赋值会发生,两个StrBlob中智能指针所指对象内存相同,计数器加一,两个StrBlobPtr中弱指针所致对象内存相同,计数器不变。
13.8
为13.1.1节(第443页)练习13.5中的HasPtr类编写赋值运算符。类似拷贝构造函数,你的赋值运算符应该将对象拷贝到ps指向的位置。
HasPtr& operator= (const HasPtr& HP)
{
string *p = new string(*HP.ps); //new返回的是指向分配好内存、创建了对象的指针
dalete ps; //首先删除原内存
ps = p; //赋值
i = HP.i;
return *this; //返回值
}
13.9
析构函数是什么?合成析构函数完成什么工作?什么时候会生成合成析构函数?
析构函数是类的一个成员函数,名字由波浪号接类名构成。它没有返回值,也不接受参数。
类似拷贝构造函数和拷贝构造运算符,对于某些类,合成析构函数用来阻止该类型的对象被销毁。如果不是这种情况,合成析构函数的函数体就为空。
当一个类未定义自己的析构函数时,编译器就会为它定义一个合成析构函数(synthesized destructor)。
13.10
当一个StrBlob对象销毁时会发生什么?一个StrBlobPtr对象销毁时呢?
所有对象的数据成员被销毁,智能指针的计数减一,所有对象的数据成员被销毁,弱指针不影响计数器。
13.11
为前面练习中的HasPtr类添加一个析构函数。
&:析构函数中,分配的动态内存对象,需要dalete。
~HasPtr() { dalete ps; } //必须首先delete对象ps,ps指向一个动态分配的string
13.12
在下面的代码片段中会发生几次析构函数调用?
bool fcn(const Sales_data *trans, Sales_data accum)
{
Sales_data item1(*trans),item2(accum);
return item1.isbn() != item2.isbn;
}
&:当指向一个对象的引用或者指针离开作用域时,析构函数不会执行。
所以,在本段代码中析构函数一共执行三次:accum,item1,item2 .
13.13 (未完成)
理解拷贝控制成员和构造函数的一个好方法是定义一个简单的类,为该类定义这些成员,每个成员都打印出自己的名字:
str