命名空間
變體
動作

預設建構函式

出自 cppreference.com
< cpp‎ | language
 
 
C++ 語言
一般主題
流程控制
條件執行陳述式
if
疊代陳述式 (迴圈)
for
範圍 for (C++11)
跳躍陳述式
函式
函式宣告
Lambda 函式運算式
inline 指定符
動態例外規範 (直到 C++17*)
noexcept 指定符 (C++11)
例外
命名空間
型別
指定符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
儲存期指定符
初始化
 
 

預設建構函式是一種無需任何引數即可呼叫的建構函式

目錄

[編輯] 語法

類別名稱 (參數列表 (可選)); (1)
類別名稱 (參數列表 (可選)) 函式主體 (2)
類別名稱 () = default; (3) (C++11 起)
類別名稱 (參數列表 (可選)) = delete; (4) (C++11 起)
類別名稱 ::類別名稱 (參數列表 (可選)) 函式主體 (5)
類別名稱 ::類別名稱 () = default; (6) (C++11 起)
class-name - 正在宣告預設建構函式的類別
參數列表 - 一個參數列表,其中所有參數(除了參數包(C++11 起)都具有預設引數
function-body - 預設建構函式的函式主體

[編輯] 解釋

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

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

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

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

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

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

如果建構函式是隱式宣告的(C++11 前)隱式宣告的或明確預設化的預設建構函式沒有定義為已刪除(C++11 起),則當其被odr-use常數求值所需(C++11 起)時,它將由編譯器隱式定義。

如果類聯集類別 (union-like class) T 的預設建構函式是平凡的,那麼對於每個聯集 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 具有一個已刪除或預設建構函式不可存取的解構函式,且 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++ 標準。

DR 應用於 出版時的行為 正確的行為
CWG 1353 C++11 隱式宣告的預設建構函式被
定義為已刪除的條件未考慮多維陣列型別
考量這些型別
CWG 2084 C++11 預設成員初始化器對於是否
聯集的預設化的預設建構函式會被刪除沒有影響
它們阻止了預設化的預設
建構函式被刪除
CWG 2595 C++20 如果存在,則預設建構函式不合資格
另一個更受約束的預設建構函式
但如果該移動建構函式未滿足其相關限制
在此情況下它可以是合格的
CWG 2871 C++98 預設建構函式將會被隱式宣告
即使存在使用者宣告的建構函式模板
沒有隱式宣告
在此情況下

[編輯] 參閱

English Deutsch 日本語 中文(简体) 中文(繁體)