很多C++新手不明白直接初始化、拷贝初始化,不清楚初始化过程中使用哪个构造函数。在学习过程中,要有基本概念,并且养成正确的认识也是非常重要的。因此整理了本文。
常见错误认识1:
1.使用()和使用=定义对象没什么区别。(直接初始化、拷贝初始化。)
2.直接初始化使用构造函数。(错,也可能使用拷贝构造函数。)
3.拷贝初始化使用拷贝构造函数。(错,也能使用构造函数。)
直接初始化
如果有一个新对象被定义(即创建了新对象),一定有构造函数被调用。
使用直接初始化时,我们实际上要求编译器使用普通的函数匹配,来提供参数最匹配的构造函数。因此直接初始化可能使用构造函数,也可能使用拷贝构造函数。
简单理解,用()来定义对象的就为直接初始化。
拷贝初始化
按字面意思理解即可,将一个对象给另一个对象初始化。
简单理解,用=定义对象的就为拷贝初始化。
注意:
拷贝赋值运算符也用在=的情况下,但是在对象已经创建并存在的情况下,只是修改对象的值而已。
而用=拷贝初始化是发生在定义一个对象的情况下,即对象此前尚未存在。
类定义如下:
#include <string>
#include <iostream>
class Book
{
public:
Book() = default;
Book(std::string s): name(s){std::cout << name << ": 1 para construstor" << std::endl;}
Book(std::string s, int n): name(s), sum(n){std::cout << name << ": 2 paras construstor" << std::endl;}
Book(const Book &b): name(b.name), sum(b.sum){std::cout << name << ": copy constructor" << std::endl;}
Book & operator = (const Book &b) {
name = b.name;
sum = b.sum;
std::cout << name << ": copy-assignment operator" << std::endl;
return *this;
}
private:
std::string name;
int sum;
};
如果有以下代码,判断,b1~b5初始化时分别使用哪个函数?
Book b1;
Book b2("b2");
Book b3 = string ("b3");
cout << endl;
Book b4(b3);
Book b5 = b3;
cout << endl;
b1 = string("b1");
1、b1:直接初始化。由于未能提供初始值,使用默认的构造函数。(想定义使用默认构造函数的对象,对象名之后不能有括号,即不能写Book b1()。这种写法意思是定义了一个叫b1的函数,返回值为Book对象。)
2、b2:直接初始化。使用了具有一个string参数的构造参数。
3、b3:拷贝初始化。使用了具有一个string参数的构造函数。
在b3初始化时,分为如下两步:
第一步:使用一个具有string参数的构造函数将string构造为临时Book类对象。
第二部:使用拷贝构造函数将上一步中的Book对象拷贝给b3。
但是实际上,编译器会进行优化,可以跳过拷贝、移动构造函数,直接使用构造函数来构造对象,即优化掉了第一步。
4、b4:直接初始化。使用了拷贝构造函数。因为括号中为Book类对象,最匹配的是拷贝构造函数。
5、b5:拷贝初始化。使用拷贝构造函数。
6、b1: 先使用构造函数将string转为Book类对象,然后将该对象通过赋值运算符来赋值给b1。
测试结果如下:
参考《C++ primer》13.1.1 P441~P442。