c++類成員初始化方式

轉載自:
https://blog.csdn.net/coder_xia/article/details/7447822

常用的初始化可能如下:

1)賦值初始化

class Student 
{
public:
	Student(string in_name, int in_age)
	{
		name = in_name;
		age = in_age;
	}
private :
	string name;
	int    age;
};

可以達到預期效果,不過不是最佳做法,因爲在構造函數中,是對name進行賦值,不是初始化,而string對象會先調用它的默認構造函數,再調用string類(貌似是basic_string類)的賦值構造函數,產生了臨時對象,速度慢;對於上例的age,因爲int是內置類型,應該是賦值的時候獲得了初值。

要對成員進行初始化,而不是賦值,可以採用初始化列表(member initialization list)改寫爲如下:

2)初始化列表

class Student 
{
public:
	Student(string in_name, int in_age):name(in_name),age(in_age) {}
private :
	string name;
	int    age;
};

結果與上例相同,不過在初始化的時候調用的是string的拷貝構造函數,而上例會調用兩次構造函數,**在分配內存空間時直接初始化,**從性能上會有不小提升

有的情況下,是必須使用初始化列表進行初始化的:const對象、引用對象

3)初始化列表初始順序

考慮以下代碼:

#include <iostream>
using namespace std;
 
class Base 
{
public:
	Base(int i) : m_j(i), m_i(m_j) {}
	Base() : m_j(0), m_i(m_j) {}
	int get_i() const
	{
		return m_i;
	}
	int get_j() const
	{
		return m_j;
	}
 
private:
	int m_i;
	int m_j;
 
};
 
int main()
{
	Base obj(98);
	cout << obj.get_i() << endl << obj.get_j() << endl;
    return 0;
}

輸出爲一個隨機數和98,爲什麼呢?

因爲對於初始化列表而言,對成員變量的初始化,是嚴格按照聲明次序,而不是在初始化列表中的順序進行初始化,如果改爲賦值初始化則不會出現這個問題,當然,爲了使用初始化列表,還是嚴格注意聲明順序吧,比如先聲明數組大小,再聲明數組這樣。

類對象的構造順序:

1.分配內存,調用構造函數時,隱式/顯示的初始化各數據成員;

2.進入構造函數後在構造函數中執行一般賦值與計算。

以下三種情況下需要使用初始化成員列表:

■ 情況一、需要初始化的數據成員是對象的情況(這裏包含了繼承情況下,通過顯示調用父類的構造函數對父類數據成員進行初始化);

■情況二、需要初始化const修飾的類成員或初始化引用成員數據;

■ 情況三、子類初始化父類的私有成員;

■情況一的說明:數據成員是對象,並且這個對象只有含參數的構造函數,沒有無參數的構造函數;

如果我們有一個類成員,它本身是一個類或者是一個結構,而且這個成員它只有一個帶參數的構造函數,而沒有默認構造函數,這時要對這個類成員進行初始化,就必須調用這個類成員的帶參數的構造函數,如果沒有初始化列表,那麼他將無法完成第一步,就會報錯。

例子:

#include "iostream"
using namespace std;
class Test
{
 public:
    Test (int, int, int){
    cout <<"Test" << endl;
 };
 private:
    int x;
    int y;
    int z;
};
class Mytest 
{
 public:
    Mytest():test(1,2,3){       //初始化
    cout << "Mytest" << endl;
    };
private:
    Test test; //聲明
};
int _tmain(int argc, _TCHAR* argv[])
{
 Mytest test;
 return 0;
}

輸出結果:

① 如果沒有mytest():test(1,2,3){}初始化列表就會報錯:

因爲Test有了顯示的帶參數的構造函數,那麼他是無法依靠編譯器生成無參構造函數的,所以沒有三個int型數據,就無法創建Test的對象。Test類對象是MyTest的成員,想要初始化這個對象test,那就只能用成員初始化列表,沒有其他辦法將參數傳遞給Test類構造函數。

②初始化列表在構造函數執行前執行(這個可以看上面的結果,對同一個變量在初始化列表和構造函數中分別初始化,首先執行參數列表,後在函數體內賦值,後者會覆蓋前者)。

■情況二的說明:對象引用或者cosnt修飾的數據成員

 情況二:當類成員中含有一個const對象時,或者是一個引用時,他們也必須要通過成員初始化列表進行初始化,因爲這兩種對象要在聲明後馬上初始化,而在構造函數中,做的是對他們的賦值,這樣是不被允許的。

例子:

class Test
{
 priate:
    const int a;             //const成員聲明
 public:
    Test():a(10){}           //初始化
};
或
class Test
{
 private:
     int &a;                        //聲明
 public:
     Test(int a):a(a){}        //初始化
}

■情況三的說明:子類初始化父類的私有成員,需要在(並且也只能在)參數初始化列表中顯示調用父類的構造函數:如下:

例子:

class Test{
public:
    Test(){};
    Test (int x){ int_x = x;};
    void show(){cout<< int_x << endl;}
private:
    int int_x;
};
class Mytest:public Test{
public:
    Mytest() :Test(110){
      //Test(110);            //  構造函數只能在初始化列表中被顯示調用,不能在構造函數內部被顯示調用
    };
};
int _tmain(int argc, _TCHAR* argv[])
{
 Test *p = new Mytest();
 p->show();
 return 0;
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章