預設構造函數

預設構造函數是C++及其他一些面向對象程序設計語言中，對象的不需要參數即可調用的構造函數。

## 概述

對象生成時如果沒有顯式地調用構造函數，則預設構造函數會被自動調用。C++標準規定，如果構造函數沒有參數（nullary），或者構造函數的所有參數都有預設值（default value），都算作預設構造函數。一個類只能有一個預設構造函數。

例如，顯式定義、使用「預設構造函數」：

```cpp
class MyClass
{
  public:
    MyClass();             // constructor declared

  private:
    int x;
};

MyClass :: MyClass()       // constructor defined   
{
    x = 100;
}

int main()
{
    MyClass object;        // object created 
}                          // => default constructor called automatically
```

下述例子是動態生成對象時，顯示調用了預設構造函數：

```cpp
int main()
{
    MyClass * pointer = new MyClass();  // object created 
}                                       // => default constructor called automatically
```

```cpp
    MyClass (int i = 0) {} 
```

C++中，預設構造函數會在下列情形被自動調用：

- 對象被定義時無參數，例如：`MyClass x;`; 或動態分配對象時無參數列表，例如：`new MyClass`或`new MyClass()`; 預設構造函數用於初始化對象。
- 對象陣列被定義時，例如：`MyClass x[10];`; 或被動態分配時，例如：`new MyClass [10]`;預設構造函數初始化陣列的每個對象。
- 當派生類在其初始化列表（initializer list）中沒有顯式調用其基類對象的構造函數時，基類的預設構造函數被自動調用。
- 當一個類的構造函數的初始化列表中沒有顯式調用其對象成員（object component或object-valued field）的構造函數時，對象成員的預設構造函數被自動調用。
- C++標準程序庫中，一些容器的填充值使用了值對象的預設構造函數，如果這些值沒有顯式地給出。例如：`vector<MyClass>(10);`用10個元素初始化vector，這些元素用其預設構造函數來初始化。

在上述這些情形中，如果被初始化地對象沒有預設構造函數，則編譯時報錯。

如果一個類沒有顯式定義構造函數，編譯器將為其隱式地定義預設構造函數（下文給出了例外情形）。隱式定義的預設構造函數的函數體為空。例如：

```cpp
class MyClass
{
    int x;                 // no constructor          
};                         // => the compiler produces an (implicit) default constructor
int main()
{
    MyClass object;        // no error: the (implicit) default constructor is called
}
```

如果類顯式地定義了一些構造函數，但不是預設構造函數，編譯器則不會為該類隱式定義預設構造函數。該類就沒有預設構造函數了。也就是說，並不是所有類都有預設構造函數。這是很多常見錯誤的原因。例如：

```cpp
class MyClass 
{
  public:
    MyClass (int y);         // a constructor     

  private:
    int x;
};
MyClass :: MyClass (int y)
{
    x = y;
}
int main()
{
    MyClass object(100);     // constructor called
    MyClass *pointer;        // for declaration do not need to know about existing constructors
    pointer = new MyClass(); // error: no default constructor    
    return 0;
}
```

如果類的基類沒有預設構造函數，那麼編譯器也不會為該類隱式地定義預設構造函數。因為該類即使隱式地定義預設構造函數，也無法初始化其基類。例如：

```cpp
class A
{
public:
	explicit A(int){}
};

class B: public A
{
};

int main()
{
	B b1;         //编译报错
}
```

如果類的基類的預設構造函數為私有，那麼編譯器會為該類隱式地定義預設構造函數，但編譯報錯「cannot access private member declared in class 基類名字」。例如：

```cpp
class A
{
   A(){};
public:
	
};

class B: public A
{
};

int main()
{
	B b1;         //编译报错
}
```

對於union數據類型，如果它包含了一個成員有非預設的構造函數，那麼這個union類型的構造函數必須顯式調用這個成員類型的構造函數。例如：

```c++
struct bar {
	bar() {};
	bar(int) {};
};
union foo { 
	int i;
	float j;
	bar b;
        // foo(): b{ } { };    //只有增加这行，才能成功地构造一个foo类型的对象
};
foo vvv;         // syntax error: attempting to reference a deleted function
```

## 進階概念

`class-name () = default;`稱作「顯式地被預設」（explicitly-defaulted）。

`class-name () = delete;`稱作「預設構造函數被刪除」（The default constructor is deleted.）。

平凡的默認構造函數（Trivial default constructor）是不執行任何操作的構造函數。所有與C語言兼容的數據類型（POD 類型）都是平凡的默認可構造。如果滿足以下所有條件，則類T的默認構造函數是平凡的（即不執行任何操作）：

- 構造函數不是使用者提供的（即，在其第一個聲明中隱式定義或默認）。
- T 沒有虛成員函數。
- T 沒有虛基類。
- T 沒有帶有預設的初始值設定項的非靜態成員（自 C++11 起）
- T 的每個直接基類都有一個平凡的默認構造函數。
- 類類型（或其陣列）的每個非靜態成員都有一個平凡的默認構造函數。

隱式聲明的默認構造函數：如果沒有為類類型提供任何類型的使用者聲明的構造函數，則編譯器總是將默認構造函數聲明為其類的內聯公共成員。如果存在一些使用者聲明的構造函數，使用者仍然可以強制編譯器使用關鍵字 default自動生成默認構造函數。（自 C++11 起）

隱式定義的默認構造函數：如果隱式聲明或「顯式地被預設」的預設構造函數未被刪除，則由編譯器定義（即生成函數體並編譯），與具有空主體和空初始值列表的使用者定義構造函數具有相同的效果。也就是說，它調用該類的基類和非靜態成員的默認構造函數。如果存在一些使用者定義的構造函數，使用者仍然可以強制編譯器自動生成默認構造函數，否則將使用關鍵字 default 隱式聲明該默認構造函數。

被刪除的預設構造函數（Deleted default constructor），如果滿足以下任一條件，則類T的隱式聲明或顯式預設的默認構造函數為已刪除(C++11起)：

- T 是一個union，其所有變體成員都是const限定類型（或是其多維陣列）。
- T 是一個非union的類，且所有匿名聯合成員都是const限定類型（或其多維陣列）。
- T 有一個引用類型的非靜態數據成員，沒有預設初始化值(C++11 起)。
- T 具有const限定類型的非變體、非靜態、非const預設可構造的數據成員（或其多維陣列），沒有預設初始化值 (C++11 起)。
- T 具有類類型為M（或其多維陣列）的潛在可構造子對象，使得M有一個析構函數，該析構函數已被刪除或無法訪問預設構造函數

如果不存在使用者定義的構造函數並且隱式聲明的預設構造函數並不平凡，則使用者仍然可以使用關鍵字delete禁止編譯器自動生成隱式定義的預設構造函數。

```cpp
 
struct F
{
    int& ref; // reference member
    const int c; // const member
    // F::F() is implicitly defined as deleted
};
```