C++之复制控制三大操作

当定义一个新类型的时候,需要显式或隐式地指定复制、赋值和撤销该类型的对象时会发生什么,这就需要三大特殊成员:复制构造函数、赋值操作符和析构函数来达到。如果没有定义复制构造函数和赋值操作符,编译器会自动定义。
这三种成员统称为复制控制,编译器自动实现这些操作,但类也可以定义自己的版本。
一、
复制构造函数是特殊的构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用,当定义一个新对象并用一个同类型的对象对他进行初始化时,将显式使用复制构造函数;当将该类型的对象传递给函数或从函数返回该类型对象时,将隐式使用复制构造函数。

应用的5种场景:
1、根据另一个同类型的对象显式或隐式初始化一个对象;
例:

 string null_book="9-999-99999-9"; //复制初始化
 string dots(10,'.');               //直接初始化
 string empty_copy=string();        //复制初始化
 string empty_direct;               //直接初始化

2、复制一个对象,将它作为实参传给一个函数。
3、从函数返回时复制一个对象;

 vector svec(5);

4、初始化顺序容器中的元素。
5、根据元素初始化式列表初始化数组元素。

 Sales_item primer_eds[]={
                          string("0-201-16487-6"),
                          string("0-201-54848-8"),
                          string("0-201-82470-1"),
                          Sales_item()
                          };

合成的复制构造函数
其行为是执行逐个成员初始化,将新对象初始化为原对象的副本。例如:

Sales_item::Sales_item(const Sales_item &orig):
       isbn(orig.isbn),
       units_sold(orig.units_sold),
       revenue(orig.revenue)
       {}

只包含类类型成员或内置类型(非指针类型)成员的类,无需显式定义复制构造函数,也可以复制。当类有指针成员时,或者有成员表示在构造函数中分配的其他资源。这两种情况都必须定义复制构造函数。

注iostrem类不允许复制。声明而不定义成员函数是合法的,但是使用未定义成员的任何尝试将导致链接失败。通过声明但不定义private复制构造函数,可禁止任何复制类类型对象的尝试:用户代码中的复制尝试将在编译时标记为错,而成员函数和友元中的复制尝试将在链接时导致错误。
大多数类应定义复制构造函数和默认构造函数

二、赋值操作符
重载操作符是一些函数,其名字为operator后跟着所定义的操作符的符号。当操作符为成员函数时,它第一个操作数隐式绑定到this指针。有些操作符(包括赋值操作符)必须定义自己的类的成员,因为赋值必须是类的成员,所以this绑定到指向左操作数的指针,因此赋值操作符接受单个形参,且该形参是同一类类型的对象,右操作数一般作为const引用传递。
赋值操作符也返回对同一类类型的引用。
例:

class Sales_item{
public:
     Sales_item& operator=(const Sales_item &);
};

合成赋值操作符会执行逐个成员赋值:右操作数对象的每个成员赋值给左操作数对象的对应成员。例如:

Sales_item&
Sales_item::operator=(const Sales_item &rhs)
{
  isbn=rhs.isbn;
  units_sold=rhs.units_sold;
  revenue=rhs.revenue;
  return *this;
}

合成赋值操作符根据成员类型使用适当的内置或类定义的赋值操作符,依次给每个成员赋值,该操作符返回*this,他是对左操作数对象的引用。
一般,如果类需要复制构造函数,他也需要赋值操作符。
三、 析构函数
是构造函数的互补:当对象超出作用域或动态分配的对象被删除时,将自动应用析构函数。析构函数可用于释放对象时构造或在对象的生命期中所获取的资源。不管类是否定义了自己的析构函数,编译器都自动执行类中非static数据成员的析构函数。
1、撤销类对象时会自动调用析构函数:

Sales_item *p=new Sales_item;
{
Sales_item item(*p);
delete p;
 }

当对象的引用或指针超出作用域时,不会运行析构函数。只有删除指向动态分配对象的指针或实际对象(非对象的引用)超出作用域时,才运行析构函数。
2、撤销一个容器时,也会运行容器中的类类型元素的析构函数:

{
Sales_item *p=new Sales_item[10];
vector vec(p,p+10);
//...
delete [ ] p;
}

容器中的元素总是按逆序撤销。
编写析构函数
分配了资源的类需要定义析构函数以释放那些资源。他是个成员函数,名字是在类名字之前加上(~),没有返回值,没有形参(因此不能重载析构函数),析构函数与复制构造函数或赋值操作符的区别是,即使自己编写了自己的析构函数,合成析构函数仍然运行。
注:撤销内置类型成员或复合类型成员没什么影响,尤其是,合成析构函数并不删除指针成员所指向的对象。

你可能感兴趣的:(C++基础)