名稱空間
變體
操作

預設建構函式

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 

預設建構函式是無需任何實參即可呼叫的建構函式

目錄

[編輯] 語法

類名 (引數列表 (可選)); (1)
類名 (引數列表 (可選)) 函式體 (2)
類名 () = default; (3) (C++11 起)
類名 (引數列表 (可選)) = delete; (4) (C++11 起)
類名 ::類名 (引數列表 (可選)) 函式體 (5)
類名 ::類名 () = default; (6) (C++11 起)
類名 - 宣告預設建構函式的類
引數列表 - 一個引數列表,其中所有引數引數包除外)(C++11 起)都有預設實參
函式體 - 預設建構函式的函式體

[編輯] 解釋

1) 在類定義內部宣告預設建構函式。
2-4) 在類定義內部定義預設建構函式。
3) 預設建構函式被顯式預設化。
4) 預設建構函式被刪除。
5,6) 在類定義外部定義預設建構函式(類必須包含宣告(1))。
6) 預設建構函式被顯式預設化。

預設建構函式在預設初始化值初始化期間呼叫。

[編輯] 隱式宣告的預設建構函式

如果類型別沒有使用者宣告的建構函式或建構函式模板,編譯器將隱式宣告一個預設建構函式作為其類的inline public成員。

隱式宣告的(或在其首次宣告時被預設化的)預設建構函式具有異常規範,如動態異常規範(C++17 前) noexcept 規範(C++17 起)中所述。

[編輯] 隱式定義的預設建構函式

如果建構函式是隱式宣告的(C++11 前)隱式宣告或顯式預設化的預設建構函式未被定義為已刪除(C++11 起),則當其被odr-使用常量求值所需(C++11 起)時,編譯器會隱式定義它。

如果類聯合`T`的預設建構函式是平凡的,那麼對於每個聯合`U`,如果`U`是`T`或`T`的匿名聯合成員,如果`U`的第一個變體成員(如果有)具有隱式生命週期型別,則`T`的預設建構函式將開始該成員的生命週期,如果它不是其聯合的活躍成員。

(C++26 起)

一個(C++26 前)否則,一個(C++26 起)隱式定義的預設建構函式具有與帶有空函式體和空初始化列表的使用者定義建構函式相同的效果。也就是說,它呼叫基類和此類的非靜態成員的預設建構函式。帶有空使用者提供建構函式的類型別在值初始化期間可能與帶有隱式定義預設建構函式的類型別被不同對待。

如果這滿足constexpr 建構函式(C++23 前)constexpr 函式(C++23 起)的要求,則生成的建構函式是constexpr

如果存在一些使用者定義的建構函式,使用者仍然可以透過關鍵字default強制編譯器自動生成原本會隱式宣告的預設建構函式。

(C++11 起)


已刪除的預設建構函式

如果滿足以下任何條件,則類`T`的隱式宣告或顯式預設化的預設建構函式被定義為已刪除

  • `T`有一個沒有預設初始化器的引用型別的非靜態資料成員。
  • `T`是一個非聯合類,並且(C++26 起)有一個非變體非靜態非const-預設可構造的const-qualified型別(或其可能的多維陣列)資料成員,且沒有預設成員初始化器。
  • `T`是一個聯合,並且其所有變體成員都是const-qualified型別(或其可能的多維陣列)。
  • `T`是一個非聯合類,並且任何匿名聯合成員的所有成員都是const-qualified型別(或其可能的多維陣列)。
(直到 C++26)
  • 給定類型別`M`,`T`具有型別`M`(或其可能的多維陣列)的潛在構造子物件obj,並且滿足以下任何條件
  • `M`有一個從預設建構函式中已刪除或不可訪問的解構函式,並且obj是非變體,或者obj有一個預設成員初始化器(C++26 起)
  • 滿足所有以下條件:
  • obj不是帶有預設初始化器的非靜態資料成員。
  • obj不是變體成員,並且其聯合中的另一個非靜態資料成員沒有預設初始化器(C++26 前)
  • 用於查詢`M`的預設建構函式的過載解析不會產生可用候選,或者在obj是變體成員的情況下,選擇了一個非平凡函式(C++26 前)

如果不存在使用者定義的建構函式,並且隱式宣告的預設建構函式不是平凡的,使用者仍然可以使用關鍵字delete來阻止編譯器自動生成隱式定義的預設建構函式。

(C++11 起)

[編輯] 平凡預設建構函式

如果滿足以下所有條件,則類`T`的預設建構函式是平凡的

  • 建構函式是隱式宣告的(C++11 前)不是使用者提供的(C++11 起)
  • `T`沒有虛成員函式。
  • `T`沒有虛基類。
  • `T`沒有帶有預設初始化器的非靜態成員。
(C++11 起)
  • `T`的每個直接基類都有一個平凡預設建構函式。
  • 類型別(或其陣列)的每個非靜態成員都有一個平凡預設建構函式。
(直到 C++26)
  • `T`要麼是一個聯合,要麼類型別(或其陣列)的每個非變體非靜態成員都有一個平凡預設建構函式。
(C++26 起)

平凡預設建構函式是不執行任何操作的建構函式。所有與C語言相容的資料型別(POD型別)都是平凡預設可構造的。

[編輯] 合格預設建構函式

預設建構函式如果是使用者宣告的,或者既是隱式宣告的又是可定義的,則它是合格的。

(C++11 前)

預設建構函式如果未被刪除,則它是合格的。

(C++11 起)
(C++20 前)

如果滿足以下所有條件,則預設建構函式是合格的

  • 它未被刪除。
  • 關聯約束(如果有)已滿足。
  • 沒有預設建構函式,其關聯的約束得到滿足,且約束更嚴格
(C++20 起)

合格預設建構函式的平凡性決定了該類是否是隱式生命週期型別,以及該類是否是平凡可複製型別

[編輯] 註釋

功能測試宏 標準 特性
__cpp_trivial_union 202502L (C++26) 放寬聯合體特殊成員函式的平凡性要求

[編輯] 示例

struct A
{
    int x;
    A(int x = 1): x(x) {} // user-defined default constructor
};
 
struct B : A
{
    // B::B() is implicitly-defined, calls A::A()
};
 
struct C
{
    A a;
    // C::C() is implicitly-defined, calls A::A()
};
 
struct D : A
{
    D(int y) : A(y) {}
    // D::D() is not declared because another constructor exists
};
 
struct E : A
{
    E(int y) : A(y) {}
    E() = default; // explicitly defaulted, calls A::A()
};
 
struct F
{
    int& ref; // reference member
    const int c; // const member
    // F::F() is implicitly defined as deleted
};
 
// user declared copy constructor (either user-provided, deleted or defaulted)
// prevents the implicit generation of a default constructor
 
struct G
{
    G(const G&) {}
    // G::G() is implicitly defined as deleted
};
 
struct H
{
    H(const H&) = delete;
    // H::H() is implicitly defined as deleted
};
 
struct I
{
    I(const I&) = default;
    // I::I() is implicitly defined as deleted
};
 
int main()
{
    A a;
    B b;
    C c;
//  D d; // compile error
    E e;
//  F f; // compile error
//  G g; // compile error
//  H h; // compile error
//  I i; // compile error
}

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 1353 C++11 隱式宣告的預設建構函式在以下情況下被
定義為已刪除,但未考慮多維陣列型別
考慮這些型別
CWG 2084 C++11 預設成員初始化器對聯合的預設建構函式是否
被刪除沒有影響
它們阻止了預設
建構函式被刪除
CWG 2595 C++20 如果存在另一個約束更嚴格的預設建構函式,則預設建構函式不合格
另一個約束更嚴格的預設建構函式
則複製建構函式不合格
它在這種情況下可以合格
CWG 2871 C++98 即使存在使用者宣告的建構函式模板,也會隱式宣告預設建構函式
即使存在使用者宣告的建構函式模板
無隱式宣告
在這種情況下

[編輯] 另請參閱