C++類和對象之初始化列表的使用方式
C++初始化列表詳解:性能優(yōu)化與正確實踐
在C++編程中,初始化列表是構(gòu)造函數(shù)的重要組成部分,它不僅能提升代碼性能,還能確保成員變量被正確初始化。本文將深入探討初始化列表的語法、應用場景及最佳實踐。
什么是初始化列表?
初始化列表是構(gòu)造函數(shù)的一部分,用于在對象創(chuàng)建時直接初始化成員變量。
它位于構(gòu)造函數(shù)參數(shù)列表之后,函數(shù)體之前,使用冒號(:
)和逗號(,
)分隔各成員的初始化操作。
class MyClass { private: int value; std::string name; const double pi; int& ref; public: // 使用初始化列表的構(gòu)造函數(shù) MyClass(int val, const std::string& nm, int& r) : value(val), name(nm), pi(3.14159), ref(r) { // 構(gòu)造函數(shù)體 } };
初始化列表的三大核心作用
1. 性能優(yōu)化:避免不必要的賦值操作
對于非基本類型(如std::string
、std::vector
),初始化列表可以直接調(diào)用其構(gòu)造函數(shù),而不是先默認構(gòu)造再賦值。
對比示例:
// 使用初始化列表(高效) class A { public: A(const std::string& str) : data(str) {} // 直接構(gòu)造 private: std::string data; }; // 使用賦值(低效) class B { public: B(const std::string& str) { data = str; } // 默認構(gòu)造 + 賦值 private: std::string data; };
2. 強制初始化:處理const和引用成員
const
成員和引用必須在初始化時賦值,初始化列表是唯一的方式。
class Config { private: const int maxSize; // 常量成員 std::string& filePath; // 引用成員 public: Config(int size, std::string& path) : maxSize(size), filePath(path) {} // 必須在初始化列表中賦值 };
3. 基類初始化:正確調(diào)用父類構(gòu)造函數(shù)
當基類沒有默認構(gòu)造函數(shù)時,必須通過初始化列表顯式調(diào)用其帶參構(gòu)造函數(shù)。
class Base { public: Base(int value) { /* ... */ } }; class Derived : public Base { public: Derived(int x) : Base(x) { /* ... */ } // 調(diào)用基類構(gòu)造函數(shù) };
4.必須使用初始化列表的情況
在C++中,引用、const成員變量以及沒有默認構(gòu)造函數(shù)的類類型成員變量必須在構(gòu)造函數(shù)初始化列表中進行初始化,這是由它們的語義和C++對象生命周期的規(guī)則決定的。
1. 引用(Reference)
引用的本質(zhì)是對象的別名,一旦綁定到某個對象就無法重新綁定。因此:
- 必須在創(chuàng)建時初始化:引用沒有“未初始化”狀態(tài),必須在定義時指定其引用的對象。
- 構(gòu)造函數(shù)體執(zhí)行前成員已初始化:構(gòu)造函數(shù)體中的代碼執(zhí)行時,成員變量已經(jīng)完成初始化。若在構(gòu)造函數(shù)體內(nèi)對引用賦值,實際上是對已初始化的引用進行賦值操作(改變被引用對象的值),而非初始化引用本身。
示例:
class Example { private: int& ref; // 引用必須初始化 public: Example(int& value) : ref(value) {} // 正確:初始化列表中初始化 };
2. const 成員變量
const
成員變量的值在對象的生命周期內(nèi)不可修改,因此:
- 必須在初始化時賦值:
const
變量一旦初始化就不能再被賦值。 - 初始化列表是唯一機會:構(gòu)造函數(shù)體執(zhí)行前,
const
成員必須已經(jīng)被賦予初始值。
示例:
class Example { private: const int value; // const成員必須初始化 public: Example(int val) : value(val) {} // 正確:初始化列表中初始化 };
3. 沒有默認構(gòu)造函數(shù)的類類型成員
如果一個類沒有默認構(gòu)造函數(shù)(即沒有無參構(gòu)造函數(shù)),則在創(chuàng)建該類的對象時必須顯式提供參數(shù)。因此:
- 必須通過參數(shù)初始化:編譯器無法默認構(gòu)造該成員,必須顯式調(diào)用其帶參構(gòu)造函數(shù)。
- 初始化列表提供了顯式調(diào)用的機會:在初始化列表中,可以指定參數(shù)來調(diào)用成員的帶參構(gòu)造函數(shù)。
示例:
class Inner { public: Inner(int x) {} // 只有帶參構(gòu)造函數(shù) }; class Example { private: Inner inner; // Inner沒有默認構(gòu)造函數(shù) public: Example(int x) : inner(x) {} // 正確:顯式調(diào)用Inner的帶參構(gòu)造函數(shù) };
為什么不能在構(gòu)造函數(shù)體中初始化?
構(gòu)造函數(shù)體中的代碼執(zhí)行時,成員變量已經(jīng)完成初始化(默認初始化或編譯器生成的初始化)。因此:
- 引用和
const
成員:無法在構(gòu)造函數(shù)體中重新初始化,因為它們必須在初始化時就確定值。 - 無默認構(gòu)造函數(shù)的類成員:如果未在初始化列表中顯式構(gòu)造,編譯器會嘗試調(diào)用其默認構(gòu)造函數(shù),但由于該類沒有默認構(gòu)造函數(shù),會導致編譯錯誤。
初始化列表的作用是在對象的內(nèi)存分配后、構(gòu)造函數(shù)體執(zhí)行前,顯式控制成員變量的初始化過程。對于引用、const
成員和無默認構(gòu)造函數(shù)的類成員,初始化列表是唯一能滿足其初始化語義的地方。若不使用初始化列表,代碼將因“未初始化的引用/const成員”或“無法默認構(gòu)造的類成員”而編譯失敗。
初始化列表的語法規(guī)則
1. 初始化順序由聲明順序決定
成員變量的初始化順序由其在類中聲明的順序決定,而非初始化列表中的順序。錯誤的順序可能導致未定義行為。
class Example { private: int a; int b; public: // 危險:初始化列表順序與聲明順序不一致 Example(int value) : b(value), a(b) {} // a先被初始化,但此時b未初始化 };
2. 支持表達式初始化
可以使用常量、函數(shù)返回值或其他成員變量進行初始化。
class Point { private: int x; int y; int distance; public: Point(int _x, int _y) : x(_x), y(_y), distance(calculateDistance(_x, _y)) {} // 使用函數(shù)返回值初始化 int calculateDistance(int x, int y) const { return std::sqrt(x*x + y*y); } };
初始化列表 vs 構(gòu)造函數(shù)體賦值
特性 | 初始化列表 | 構(gòu)造函數(shù)體賦值 |
---|---|---|
執(zhí)行時機 | 對象創(chuàng)建時 | 對象創(chuàng)建后 |
性能 | 通常更高效 | 可能涉及額外的賦值操作 |
const/引用成員 | 支持 | 不支持 |
基類初始化 | 必須使用 | 不可用 |
總結(jié)
初始化列表總結(jié):
- 無論是否顯?寫初始化列表,每個構(gòu)造函數(shù)都有初始化列表;
- 無論是否在初始化列表顯?初始化成員變量,每個成員變量都要?初始化列表初始化;
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
C++編程使用findfirst和findnext查找及遍歷文件實現(xiàn)示例
這篇文章主要為大家介紹了C++編程如何使用findfirst和findnext查找及遍歷文件實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-10-10

C++11中std::thread線程實現(xiàn)暫停(掛起)功能