直接初始化、拷贝初始化、赋值运算符
5.1直接初始化:通过匹配构造函数参数,直接调用构造函数(包含拷贝构造函数)完成初始化。
5.2拷贝初始化:拷贝对象副本,或者对象右值引用,再通过调用拷贝构造函数或者移动构造函数实现初始化对象。
拷贝初始化发生的6种情况:
//other:已有的对象
T object = other; //(1) 使用等号,且非引用类型
T object = {other}; //(2) (until C++11)使用等号,且非引用类型
f(other) //(3)做为对象为一个值,作为函数实参:值传递
return other; //(4)//返回对象的值
throw object;
catch (T object)//(5) 对象作为值类型的异常
T array[N] = {other}; //(6)作为聚合初始化的一部分
对应的解释:
Copy initialization is performed in the following situations:
-
when a named variable (automatic, static, or thread-local) of a non-reference type
T
is declared with the initializer consisting of an equals sign followed by an expression. -
(until C++11)when a named variable of a scalar type
T
is declared with the initializer consisting of an equals sign followed by a brace-enclosed expression (Note: as of C++11, this is classified as list initialization, and narrowing conversion is not allowed). -
when passing an argument to a function by value
-
when returning from a function that returns by value
-
as part of aggregate initialization, to initialize each element for which an initializer is provided
重点谈一下拷贝构造函数,定义如下:
A copy constructor is a special constructor for a class/struct that is used to make a copy of an existing instance.
翻译一下:拷贝构造函数是class/struct的一种特殊构造函数,拷贝构造函数通过拷贝(copy)已经出现的实例(对象)来实现构造,
foo (const foo&);//拷贝构造函数声明,foo类名,
//拷贝构造函数的形参必须是引用类型的原因:
// 如果不是引用类型,为了调用拷贝构造函数,我们必须拷贝它的实参,但为了拷贝实参,我们又需要调用拷贝构造函数,如此无限循环,造成错误。
拷贝初始化调用拷贝构造函数时,一定会先拷贝实例对象的临时副本,然后调用拷贝构造函数:可以观察拷贝初始化发生的6种情况,函数参数值传递、返回值一定会创建对象临时副本的情况。拷贝初始化利用拷贝构造函数时,应该是先调用对应的构造函数创建一个临时对象,然后拷贝构造函数(调用引用传递)再将构造的临时对象拷贝给要创建的对象。
再来看一下c++primer的例子,重点关注string s(dots);
和string s2 = dots;
,这两个都调用了拷贝构造函数,但是初始化方式不同。理解上面的内容,就比较好解释这种现象了:
string dots(10,'.'); //直接初始化
string s(dots); //直接初始化,直接匹配拷贝构造函数参数,进而直接调用拷贝构造函数,属于直接初始化
string s2 = dots; //拷贝初始化,先创建dots的副本,然后将副本做为参数传递给拷贝构造函数,属于拷贝初始化
string null_book = "9-999-99999-9"; //拷贝初始化,进行了隐式转换,即:char* to string
string nines = string(100,'9'); //拷贝初始化
**5.3赋值运算符:**使用一个对象赋值(=)给一个已经存在的对象。赋值和初始化有区别(参考前面的文章),因此拷贝初始化过程的=号不是赋值符号。
The equals sign,=,in copy-initialization of a named variable is not related to the assignment operator. Assignment operator overloads have no effect on copy-initialization.
拷贝构造函数与赋值运算符的区别
(1)从概念上区分:
拷贝构造函数是构造函数,而赋值操作符属于操作符重载范畴,它通常是类的成员函数
(2)从原型上来区分:
拷贝构造函数原型ClassType(const ClassType &);无返回值
赋值操作符原型ClassType& operator=(const ClassType &);返回值为ClassType的引用,便于连续赋值操作
(3)从使用的场合来区分:
拷贝构造函数用于产生对象,而赋值操作符要求‘=’的左右对象均已存在,它的作用就是把‘=’右边的对象的值赋给左边的对象。
拷贝构造函数是去完成对未初始化的存储区的初始化,而赋值操作符则是处理一个已经存在的对象。对一个对象赋值,当它一次出现时,它将调用拷贝构造函数,以后每次出现,都调用赋值操作符。
5.4参考
c++primer 13.1