在c++11中,类是和5个特殊的函数紧密相关的,它们是析构函数、拷贝构造函数、移动构造函数、拷贝赋值运算符和移动赋值运算符。
析构函数
只要一个对象运行越出范围,或经受一次delete,则析构函数就要被调用。典型情况下,析构函数的唯一责任就是释放掉在对象使用期间获得的资源,包括关于任意的new操作调用对应的delete,关闭任何打开的文件,等等。默认做法是对每个数据成员应用析构函数。
拷贝构造函数和移动构造函数
有两个特殊的构造函数用来构造一个新的对象,它被初始化为与另一个同样类型对象相同的状态。如果这个已存在的对象是一个左值,那么就用拷贝构造函数;而如果这个已存在的对象是一个右值(即一个迟早要被删除的临时量),那么就用移动构造函数。对于任意对象,例如IntCell这样的对象,在下述实例中将调用拷贝构造函数或移动构造函数:
带初始化的声明,如
IntCell B = C; //若C是左值则调用拷贝构造函数;若C是右值则调用移动构造函数
IntCell B { C }; //若C是左值则调用拷贝构造函数; 若C是右值则调用移动构造函数
但不适用于
B = C; //赋值运算符
拷贝赋值和移动赋值(operator=)
当=用于两个先前均被构造过的对象时,则调用赋值运算符。lhs=rhs 是要拷贝 rhs的状态到lhs上。如果rhs是一个左值,那么这可通过使用拷贝赋值运算符完成;如果rhs是一个右值,那么这可通过使用移动运算符做到。默认时,拷贝赋值运算符是通过依次把拷贝赋值运算符用于每一个数据成员而被实现的。
默认情形
一个其数据成员是int、double、vector<int>、string甚至vector<string>的类均可接受默认情形,而包含指针作为数据成员的类则往往不行。
我们首先声明并显示定义所有5个函数的默认情形。对于IntCell,这些操作的形式是
~IntCell(); //析构函数
IntCell(const IntCell & rhs ); //拷贝构造函数
IntCell(IntCell && rhs); //移动构造函数
IntCell & operator= (const IntCell & rhs); //拷贝赋值
IntCell & operator= (IntCell && rhs); //移动赋值
当默认操作不起作用时
最常见的默认操作不起作用的情况出现在数据成员为指针类型。、
数据成员是指针时,写出五大函数
class IntCell
{
public:
explicit IntCell(int initialValue = 0)
{
storedValue = new int{ initialValue};
}
~IntCell() //析构函数
{
delete storedValue;
}
IntCell(const IntCell & rhs) //拷贝构造函数
{
storedValue = new int{*rhs.storedValue};
}
IntCell(IntCell && rhs): storedValue{rhs.storedValue} //移动构造函数
{
rhs.storedValue = nullptr;
}
IntCell & operator = (const IntCell & rhs) //拷贝赋值
{
if(this != &rhs)
*storedValue = *rhs.storedValue;
return *this;
}
IntCell & operator=(IntCell && rhs) //移动赋值
{
std::swap(storedValue,rhs.storedValue);
return *this;
}
int read() const
{
return *storedValue;
}
void write(int x)
{
*storedValue = x;
}
private:
int *storedValue;
};