天天看點

C++ 類的靜态成員詳細講解

在C++中,靜态成員是屬于整個類的而不是某個對象,靜态成員變量隻存儲一份供所有對象共用。是以在所有對象中都可以共享它。使用靜态成員變量實作多個對象之間的資料共享不會破壞隐藏的原則,保證了安全性還可以節省記憶體。

靜态成員的定義或聲明要加個關鍵static。靜态成員可以通過雙冒号來使用即<類名>::<靜态成員名>。

在C++中類的靜态成員變量和靜态成員函數是個容易出錯的地方,本文先通過幾個例子來總結靜态成員變量和成員函數使用規則,再給出一個執行個體來加深印象。希望閱讀本文可以使讀者對類的靜态成員變量和成員函數有更為深刻的認識。

第一個例子,通過類名調用靜态成員函數和非靜态成員函數

class Point

{

public:   

       void init()

       { 

       }

       static void output()

       {

};

void main()

       Point::init();

       Point::output();

}

編譯出錯:error C2352: 'Point::init' : illegal call of non-static member function

結論1:不能通過類名來調用類的非靜态成員函數。

第二個例子,通過類的對象調用靜态成員函數和非靜态成員函數

将上例的main()改為:

       Point pt;

       pt.init();

       pt.output();

編譯通過。

結論2:類的對象可以使用靜态成員函數和非靜态成員函數。

第三個例子,在類的靜态成員函數中使用類的非靜态成員

#include <stdio.h>

              printf("%d\n", m_x);

private:

       int m_x;

編譯出錯:error C2597: illegal reference to data member 'Point::m_x' in a static member function

因為靜态成員函數屬于整個類,在類執行個體化對象之前就已經配置設定空間了,而類的非靜态成員必須在類執行個體化對象後才有記憶體空間,是以這個調用就出錯了,就好比沒有聲明一個變量卻提前使用它一樣。

結論3:靜态成員函數中不能引用非靜态成員。

第四個例子,在類的非靜态成員函數中使用類的靜态成員

              output();

結論4:類的非靜态成員函數可以調用用靜态成員函數,但反之不能。

第五個例子,使用類的靜态成員變量

       Point()

              m_nPointCount++;

       ~Point()

              m_nPointCount--;

              printf("%d\n", m_nPointCount);

       static int m_nPointCount;

按Ctrl+F7編譯無錯誤,按F7生成EXE程式時報連結錯誤

error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA)

這是因為類的靜态成員變量在使用前必須先初始化。

在main()函數前加上int Point::m_nPointCount = 0;

再編譯連結無錯誤,運作程式将輸出1。

結論5:類的靜态成員變量必須先初始化再使用。

結合上面的五個例子,對類的靜态成員變量和成員函數作個總結:

一。靜态成員函數中不能調用非靜态成員。

二。非靜态成員函數中可以調用靜态成員。因為靜态成員屬于類本身,在類的對象産生之前就已經存在了,是以在非靜态成員函數中是可以調用靜态成員的。

三。靜态成員變量使用前必須先初始化(如int MyClass::m_nNumber = 0;),否則會在linker時出錯。

再給一個利用類的靜态成員變量和函數的例子以加深了解,這個例子建立一個學生類,每個學生類的對象将組成一個雙向連結清單,用一個靜态成員變量記錄這個雙向連結清單的表頭,一個靜态成員函數輸出這個雙向連結清單。

#include <string.h>

const int MAX_NAME_SIZE = 30; 

class Student 

public: 

    Student(char *pszName);

    ~Student();

public:

       static void PrintfAllStudents();

private: 

    char    m_name[MAX_NAME_SIZE]; 

    Student *next;

       Student *prev;

    static Student *m_head;

}; 

Student::Student(char *pszName)

    strcpy(this->m_name, pszName);

       //建立雙向連結清單,新資料從連結清單頭部插入。

    this->next = m_head;

       this->prev = NULL;

       if (m_head != NULL)

              m_head->prev = this;

    m_head = this; 

Student::~Student ()//析構過程就是節點的脫離過程 

       if (this == m_head) //該節點就是頭節點。

              m_head = this->next;

       else

              this->prev->next = this->next;

              this->next->prev = this->prev;

void Student::PrintfAllStudents()

       for (Student *p = m_head; p != NULL; p = p->next)

              printf("%s\n", p->m_name);

Student* Student::m_head = NULL; 

void main() 

{  

       Student studentA("AAA");

       Student studentB("BBB");

       Student studentC("CCC");

       Student studentD("DDD");

       Student student("MoreWindows");

       Student::PrintfAllStudents();

程式将輸出:

C++ 類的靜态成員詳細講解

當然在本例還可以增加個靜态成員變量來表示連結清單中學生個數,如果讀者有興趣,就将這個作為小練習吧。

繼續閱讀