C++知識點隨筆(三):static、const、friend、inline

吃不夠的圓兒寶發表於2015-07-07

一、static

靜態成員屬性為什麼要在類外初始化?
靜態成員屬性之所以不能在建構函式內初始化,是因為建構函式必須要在定義物件的時候才會呼叫,而static變數在編譯的時候就建立了,所以要在類外通過類名作用域對static成員屬性初始化。

注意:sizeof()在C++中和C語言有不同,當我們:

cout << sizeof(//類名) << endl;

的時候,不是輸出這個類的大小,而是輸出定義一個這個類的物件需要申請多大的空間,所以如果這個類裡包含了靜態成員都不會計算在sizeof()內的,因為靜態成員一個類只有一份兒,所以的物件共用他們。

struct Node
{
    int age;
    char c;
};

class CPeople
{
public:
    int pp;
    static const int qq = 100;   //靜態常量整形資料成員才能在類內初始化
    static Node node[2];
    static int num;    // 靜態成員一定要在類外初始化
public:      //相當於全域性變數,在編譯的時候就申請空間了,不用物件也能呼叫,(類名::)
    CPeople()
    {
        pp = 100;
    }
    //  靜態成員函式:不能用普通的成員屬性,只能用 static 成員,因為沒有this指標
    static void Show()
    {
        //cout << this->pp << endl;     
        cout << num << endl;
        cout << "static::show" << endl;
    }
};
Node CPeople::node[2] = {{123,'d'},{456,'y'}};  //靜態結構體陣列初始化
int CPeople::num = 123;   //靜態成員的初始化

注意:靜態常量整形資料成員才能在類內初始化。所以short、long、char都可以,但是float、double不可以。

二、const

非靜態const成員屬性為什麼一定要在初始化列表裡進行初始化?
在C中我們知道#define進行預定義的某個數是被分配記憶體的,其檔案在編譯預處理過程中就會用定義好的資料去替代文中的符號。但是const卻是不一樣的,一般情況下編譯器也是不為const建立空間的,只是將這個定義的數字儲存在符號表中的。所以C++中const是在編譯的時候定義的,但是它的初始化可以在呼叫建構函式(也就是建立物件)的時候通過初始化列表的方式進行。呼叫建構函式的時候,首先是給該例項(類的具體物件)分配空間。使用初始化列表的話,就在分配空間的時候,同時將其空間初始化。但在建構函式的大括號裡,所有變(常)量的空間都已經分配好了,進行賦值操作。我們知道const是常量,只能進行初始化操作而不能進行賦值操作,所以必須在初始化列表中分配空間的同時進行初始化操作。

還有一個賦值次數,效率上的區別,初始化列表在物件初始化時對成員變數賦值一次,而使用建構函式內直接賦值的話,對成員變數賦值兩次,一次是物件構造是用預設值進行賦值,第二次是呼叫建構函式賦值。因為普通成員變數是否初始化都可以,而且允許賦值操作,所以普通成員變數既可以使用初始化列表又可以使用建構函式賦值。

參考:http://blog.csdn.net/zhouyelihua/article/details/23252667

const成員函式

void Show(/*const CPeople* this*/) const   // 常函式,不能修改類中的成員屬性
{                               
    //this->a = 100;   //錯誤,因為 this 已經變成 const CPeople* this
}

常量型別的物件:

const CPeople pep;

只能呼叫常函式,普通函式用不了,因為我們知道成員函式在使用的時候要把物件的地址傳進去,而我們用常量物件呼叫普通成員變數的時候,相當於:

void AA(/*CPeople* this = const CPeople* ll*/)
{
    a = 567;
}

一定會報錯的。而const成員函式的this已經變了,所以常量物件可以呼叫const成員函式。反過來普通物件可以呼叫常函式。

三、friend

friend class BB;                // 友元類
friend void Show(CPeople pp);   // 友元函式,可以讓這個東西用自己的private成員

無論是友元類還是被友元類,都不能繼承這個友元關係。友元的友元也不能使用。友元就是只限定這一個可以用

類的封裝性問題
友元函式是破壞類的封裝性的最大殺手。我們在使用成員函式返回類的私有成員屬性的時候也是很危險的,如果一定要使用的話,就將返回值設為const。

四、inline

void AA()    // 類內實現的都是行內函數(預設的)
{
    cout << "AA" << endl;
}
/*inline */void BB();    //  不是內聯的 
inline void BB();    //  內聯的

不過編譯器自己也會有判斷,其實宣告為inline只是對編譯器提出一個建議,建議編譯器進行內聯,而具體會不會內聯,由編譯器決定,編譯器會綜合考慮更方面因素來判斷要不要進行內聯。
內聯將函式程式碼直接在呼叫的地方展開,而函式呼叫是一個跳轉語句,通過函式指標跳轉到函式體的地址,執行完再回來,所以inline是一種用空間換時間的方法。

參考我的另一篇部落格:http://blog.csdn.net/u012300157/article/details/46763089

相關文章