很多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。