拷贝控制之拷贝构造函数

当我们定义一个类的时候。我们通常会显式或隐式的指定在此类的对象在创建、移动、销毁的时候要做些什么。

一个类通常通过定义五种特殊的成员函数来控制这些操作:拷贝构造函数、拷贝赋值函数、移动构造函数、移动赋值运算符、析构函数。

如果我们没有定义这些成员函数,编译器会自动定义些缺失的操作。有时也会造成些意想不到的错误。

拷贝构造函数:

如果一个构造函数的第一个参数是自身类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数。

class Foo{
public:
    Foo();              //默认构造函数
    Foo(const Foo&);    //拷贝构造函数
   //...
};   

拷贝构造函数第一个参数必须是引用类型。(原因后面解释)

拷贝构造函数参数几乎总是一个const的引用。

拷贝构造函数会经常被隐式的使用,所以通常不应该声明成explicit。

合成拷贝构造函数

如果未定义拷贝构造函数,编译器会为我们定义一个。

即使定义了其他构造函数,编译器也会为我们合成一个拷贝构造函数。

一般情况,编译器从给定对象中一次将每个非static成员拷贝到正在创建的对象当中。

对类类型的成员,则调用他的合成拷贝函数。对于其他类型的成员,则直接拷贝。

拷贝初始化

我们可以从下面几个例子里看出初始化与拷贝初始化的不同。

string dots(10, '.');        //直接初始化
string s(dots);              //直接初始化
string s2 = dots;            //拷贝初始化
string null_book = "9-999-99999-9";   //拷贝初始化
string nines = string(100, '9');      //拷贝初始化

现在,只用了解拷贝初始化何时发生,以及拷贝初始是依靠拷贝构造函数或移动构造函数来完成的。

不仅在=定义变量时会发生,还会在下列情况发生:

  ·将一个对象作为实参传递给非引用类型的形参。

  ·从一个返回类型为非引用类型的函数返回一个对象。

  ·用花括号列表初始化数组元素或一个聚合类的成员。

当初始化标准库容器或调用其insert或push函数时,会使用拷贝初始化。

用emplace成员创建的元素都进行直接初始化。

参数和返回值

在函数调用过程中,具有非引用类型的参数要进行拷贝初始化。当一个函数具有非引用类型的返回类型时,返回值会被用来初始化调用方法的结果。

拷贝构造函数被用来初始化非引用类型的参数。所以拷贝构造函数的参数必须是引用类型。

猜你喜欢

转载自blog.csdn.net/qq_32835707/article/details/81607736