C++直接初始化,拷貝初始化,調用哪個構造函數?

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章