C++:20---成員變數初始化方式
成員變數初始化有三種方式:
在建構函式體內賦值初始化
在自定義的公有函式體中賦值初始化(一般用於成員變數的初始化)
在建構函式的成員初始化列表初始化
一、建構函式體內初始化
說明:在建構函式體內的初始化方式,本質是是為成員變數賦值,而不是真正意義上的初始化,這點要特別注意!(下面介紹成員初始化列表時會有演示案例對比說明)
class Cperson{private:int m_age;float m_height;char* m_name;public:Cperson(int age,float height,const char* name){m_age=age;m_height=height;if(m_name)//先判斷當前是否為空delete[] m_name;if(name)//如果外部傳入的不為空{int len=strlen(name);m_name=new char[len+1];//建立記憶體strcpy(t m_name,name);}elsem_name=nullptr;}}
二、自定義的公有函式體中賦值初始化
說明:與建構函式體內初始化方式一樣,此種方式本質上也是賦值,而不是初始化
class Cperson{private:int m_age;float m_height;char* m_name;public:void setPerson(int age,float height,const char* name){m_age=age;m_height=height;if(m_name)//先判斷當前是否為空delete[] m_name;if(name)//如果外部傳入的不為空{int len=strlen(name);m_name=new char[len+1];//建立記憶體strcpy(t m_name,name);}elsem_name=nullptr;}}
三、成員初始化列表初始化
特點:
初始化順序與書寫的在建構函式後的順序無關,而與成員變數的定義順序有關(下面有演示案例)
初始化列表初始化優先於建構函式內的程式碼執行順序
寫在建構函式的後面,隨著建構函式的執行而執行
初始化順序:
多個成員之間用逗號隔開,括號內為形參
一般只對無動態記憶體的成員、const成員、引用初始化(const成員、引用成員必須在初始化列表初始化)
成員初始化列表初始化效率更高(下面有演示案例)
有動態記憶體的成員必須在建構函式內部進行初始化(為什麼?因為動態記憶體不能進行簡單的賦值,因此所存在的地址不同,要自己申請動態記憶體並初始化)。牢記:內部資料內部處理,外部資料外部處理
class Cperson{private:int m_age;float m_height;char* m_name;public:Cperson(int age,float height,const char* name);}//m_name為指標型別,需要自己申請空間Cperson::Cperson(int age,float height,const char* name):m_age(age),m_height(height){if(m_name)//先判斷當前是否為空delete[] m_name;if(name)//如果外部傳入的不為空{int len=strlen(name);m_name=new char[len+1];//建立記憶體strcpy(m_name,name);}elsem_name=nullptr;}
成員的初始化順序
成員初始化的順序,與在建構函式後面書寫的順序無關。而與成員變數定義的順序有關
例如下面的程式碼,在建構函式花括號後m_height放在m_age前面,但是先初始化m_age再初始化m_height,因為m_age先定義
class Cperson{private:int m_age;float m_height;public:Cperson(int age,float height);}Cperson::Cperson(int age,float height):m_height(height),m_age(age){}
錯誤事例(初始化順序導致的錯誤)
一個特殊情況:如果用一個成員變數去初始化另一個成員變數,就要注意初始化順序了
因此,我們在初始化的時候,儘量避免用某些成員去初始化另一個成員
//下面程式碼中,i先被初始化,但是i是根據j初始化的,但j後初始化,就會產生不好的後果class X{int i;int j;public:X(int value):j(value),i(j){}};
更正:因為初始化列表初始化比建構函式內初始化早,所以可以將上面的程式碼改為下面的形式就不會出錯了
class X{int i;int j;public://j先初始化,i再初始化X(int value):j(value){i(j);}};
錯誤事例(針對const成員與引用成員)
此案例強調是的,const成員和引用必須在成員初始化列表進行初始化
class Person{private:const int id;int& m_id;public:Person(int i);};Person::Person(int i){id=i;//錯誤,const成員變數必須在成員初始化列表初始化m_id=id;//錯誤,引用也必須在成員初始化列表初始化}
演示案例(成員初始化列表初始化效率更高)
例如下面在建構函式內對兩個成員進行初始化
class Word{string _name;int _cnt;public:Word(){_name=0;//先建立一個臨時string物件,賦值為0,然後拷貝給_name_cnt=0;//建構函式結束之後,臨時物件析構釋放}};
但是如果使用下面的成員初始化列表初始化,那麼就省去了建立臨時物件再拷貝的過程,因此成員初始化列表初始化的效率更高
class Word{string _name;int _cnt;public:Word():_name(0),_cnt(0){} //直接初始化_name,不建立臨時物件};
四、初始化方式總結
根據上面的三種方式,總結出:成員初始化列表初始化成員才是真正意義上的初始化,其他兩種方式都是為賦值
初始化和賦值涉及到底層效率的問題:初始化是直接初始化。而賦值是先初始化一個臨時變數,再賦值。前者效率高