1. 程式人生 > >第6課 列表初始化(1)_統一初始化

第6課 列表初始化(1)_統一初始化

nio 概念 基類 class 臨時對象 clas 靜態 logs char

1. 統一初始化(Uniform Initialization)

(1)在C++11之前,很多程序員特別是初學者對如何初始化一個變化或對象的問題很容易出現困惑。因為可以用小括號、大括號或賦值操作符等多種方式進行初始化

(2)基於這個原因,C++11引入了“統一初始化”的概念。這意味著我們可以使用{}這種通用的語法在任何需要初始化的地方。

【實例分析】初始化列表

#include <iostream>
#include <vector>
#include <map>
using namespace std;

//編譯選項:g++ -std=c++11 test1.cpp
struct Test { int x; int y; } test {123, 321}; //等價於test = {123,321} int main() { int i; //未初始化 int j{}; //j被初始化為0 int* p; //未初始化 int* q{}; //j被初始化為nullptr int* a = new int{123}; //等價於int* x=new int(123); double b = double{12.12}; //等價於double(12.12)產生一個臨時對象,再拷貝初始化 int
* arr = new int[3]{1, 2, 3}; //C++11中新增的初始化堆上數組的方式 std::map<std::string, int> mm {{"2", 1},{"2", 2}, {"3", 3}}; //相當於map<string,int> mm = {...}; cout << test.x << endl; cout << test.y << endl; return 0; }

2. 列表初始化的使用細節

(1)引入初始化列表(initializer-list)出現的一些模糊概念

//x,y究竟為0,0還是123,321?
struct A
{
  int x;
  int y;

  A(int,int):x(0), y(0){} //非聚合類型,使用{}初始化時會調用相應的構造函數
} a = {123, 321};  //a.x=0, a.y=0

(2)聚合類型的定義

  ①類型是一個普通類型的數組(如int[10]、char[]、long[2][3])

  ②類型是一個類(class、struct或union),且:

    A.無基類、無虛函數以及無用戶自定義的構造函數。

    B.無private或protected的普通數據成員(即非靜態數據成員)。

    C.不能有{}和=直接初始化的非靜態數據成員(“就地初始化”)

【實例分析】聚合類型與非聚合類型的初始化

#include <iostream>
using namespace std;

struct Base{};

//聚合類型的定義
struct Foo : public Base //不能有基類
{
private:
    double z;      //不能有private的普通成員
    static int k;  //ok,但必須在類外用int Foo::k = 0的方式初始化
public:
    Foo(int x, int y, double z):x(x),y(y),z(z) //不能有構造函數!
    {
        cout<< "Foo(int x, int y, double z)" << endl;
    } 
    
    Foo(const Foo& foo)  //不能有構造函數!
    {
        this->x = foo.x;
        this->y = foo.y;
        this->z = foo.z;
        
        cout<< "Foo(const Foo& foo)" << endl;
    }
    
    int x;
    int y; //不能通過int y=0;或int y{0}來"就地初始化"
    virtual void F(){}; //不能有虛函數!
        
};

Foo f1(1, 2, 3.0);     //直接調用構造函數初始化
Foo f2{4, 5, 6.0};     //由於Foo是個非聚合類型,使用{}時會調用相應的構造函數來初始化。
Foo f3 = {7, 8, 9.0};  //非聚合類型會調用構造函數來初始化

int main()
{
    cout << a.x << endl;
    cout << a.y << endl;
    return 0;
}
/*輸出結果:
Foo(int x, int y, double z)
Foo(int x, int y, double z)
Foo(int x, int y, double z)
*/

(3)註意事項

  ①聚合類型的定義是非遞歸的。簡單來說,當一個類的普通成員是非聚合類型時,這個類也有可能是聚合類型,也就是說可以直接用列表初始化。

  ②對於一個聚合類型可以直接使用{}進行初始化,這時相當於對其中每個元素分別賦值;而對於非聚合類型,則需要先自定義一個合適的構造函數才能使用{}進行初始化,此時使用初始化列表將調用它對應的構造函數。

第6課 列表初始化(1)_統一初始化