为前面练习中的 HasPtr 类添加一个析构函数。
#ifndef ex13_11_h
#define ex13_11_h
#include
class HasPtr
{
public:
HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) {}
HasPtr(const HasPtr &hp) : ps(new std::string(*hp.ps)), i(hp.i) {}
HasPtr& operator=(const HasPtr &hp)
{
std::string *new_ps = new std::string(*hp.ps);
delete ps;
ps = new_ps;
i = hp.i;
return *this;
}
~HasPtr()
{
delete ps;
}
private:
std::string *ps;
int i;
};
#endif // !ex13_11_h
在下面的代码片段中会发生几次析构函数调用?
bool fcn(const Sales_data *trans, Sales_data accum)
{
Sales_data item1(*trans), item2(accum);
return item1.isbn() != item2.isbn();
}
三次,分别是 accum、item1和item2。
理解拷贝控制成员和构造函数的一个好方法的定义一个简单的类,为该类定义这些成员,每个成员都打印出自己的名字:
struct X {
X() {std::cout << "X()" << std::endl;}
X(const X&) {std::cout << "X(const X&)" << std::endl;}
}
给 X 添加拷贝赋值运算符和析构函数,并编写一个程序以不同的方式使用 X 的对象:将它们作为非引用参数传递;动态分配它们;将它们存放于容器中;诸如此类。观察程序的输出,直到你确认理解了什么时候会使用拷贝控制成员,以及为什么会使用它们。当你观察程序输出时,记住编译器可以略过对拷贝构造函数的调用。
假定 numbered 是一个类,它有一个默认构造函数,能为每个对象生成一个唯一的序号,保存在名为 mysn 的数据成员中。假定 numbered 使用合成的拷贝控制成员,并给定如下函数:
void f (numbered s) { cout << s.mysn < endl; }
则下面代码输出什么内容?
numbered a, b = a, c = b;
f(a); f(b); f(c);
输出3个完全一样的数。
假定numbered 定义了一个拷贝构造函数,能生成一个新的序列号。这会改变上一题中调用的输出结果吗?如果会改变,为什么?新的输出结果是什么?
会输出3个不同的数。并且这3个数并不是a、b、c当中的数。
如果 f 中的参数是 const numbered&,将会怎样?这会改变输出结果吗?如果会改变,为什么?新的输出结果是什么?
会输出 a、b、c的数。
分别编写前三题中所描述的 numbered 和 f,验证你是否正确预测了输出结果。
//13.14
#include
class numbered
{
public:
numbered()
{
mysn = unique++;
}
int mysn;
static int unique;
};
int numbered::unique = 10;
void f(numbered s)
{
std::cout << s.mysn << std::endl;
}
int main()
{
numbered a, b = a, c = b;
f(a);
f(b);
f(c);
}
//13.15
#include
class numbered {
public:
numbered() {
mysn = unique++;
}
numbered(const numbered& n)
{
mysn = unique++;
}
int mysn;
static int unique;
};
int numbered::unique = 10;
void f(numbered s) {
std::cout << s.mysn << std::endl;
}
int main()
{
numbered a, b = a, c = b;
f(a);
f(b);
f(c);
}
//13.16
#include
class numbered
{
public:
numbered()
{
mysn = unique++;
}
numbered(const numbered& n)
{
mysn = unique++;
}
int mysn;
static int unique;
};
int numbered::unique = 10;
void f(const numbered& s)
{
std::cout << s.mysn << std::endl;
}
int main()
{
numbered a, b = a, c = b;
f(a);
f(b);
f(c);
}
定义一个 Employee 类,它包含雇员的姓名和唯一的雇员证号。为这个类定义默认构造函数,以及接受一个表示雇员姓名的 string 的构造函数。每个构造函数应该通过递增一个 static 数据成员来生成一个唯一的证号。
#ifndef ex13_18_h
#define ex13_18_h
#include
using std::string;
class Employee
{
public:
Employee();
Employee(const string& name);
const int id() const { return id_; }
private:
string name_;
int id_;
static int s_increment;
};
int Employee::s_increment = 0;
Employee::Employee()
{
id_ = s_increment++;
}
Employee::Employee(const string& name)
{
id_ = s_increment++;
name_ = name;
}
#endif
你的 Employee 类需要定义它自己的拷贝控制成员吗?如果需要,为什么?如果不需要,为什么?实现你认为 Employee 需要的拷贝控制成员。
#ifndef ex13_19_h
#define ex13_19_h
#include
using std::string;
class Employee
{
public:
Employee();
Employee(const string &name);
Employee(const Employee&) = delete;
Employee& operator=(const Employee&) = delete;
const int id() const { return id_; }
private:
string name_;
int id_;
static int s_increment;
};
#endif
解释当我们拷贝、赋值或销毁 TextQuery 和 QueryResult 类对象时会发生什么?
成员会被复制。