在C++中疤剑,靜態(tài)成員是屬于整個類的而不是某個對象璃谨,靜態(tài)成員變量只存儲一份供所有對象共用。所以在所有對象中都可以共享它豁辉。使用靜態(tài)成員變量實現(xiàn)多個對象之間的數(shù)據(jù)共享不會破壞隱藏的原則阳柔,保證了安全性還可以節(jié)省內(nèi)存焰枢。靜態(tài)成員的定義或聲明要加個關(guān)鍵static。靜態(tài)成員可以通過雙冒號來使用即<類名>::<靜態(tài)成員名>舌剂。
在C++中類的靜態(tài)成員變量和靜態(tài)成員函數(shù)是個容易出錯的地方济锄,本文先通過幾個例子來總結(jié)靜態(tài)成員變量和成員函數(shù)使用規(guī)則,再給出一個實例來加深印象霍转。希望閱讀本文可以使讀者對類的靜態(tài)成員變量和成員函數(shù)有更為深刻的認(rèn)識拟淮。
第一個例子,通過類名調(diào)用靜態(tài)成員函數(shù)和非靜態(tài)成員函數(shù)
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
結(jié)論1:不能通過類名來調(diào)用類的非靜態(tài)成員函數(shù)谴忧。
第二個例子很泊,通過類的對象調(diào)用靜態(tài)成員函數(shù)和非靜態(tài)成員函數(shù)
將上例的main()改為:
void main()
{
Point pt;
pt.init();
pt.output();
}
編譯通過。
結(jié)論2:類的對象可以使用靜態(tài)成員函數(shù)和非靜態(tài)成員函數(shù)沾谓。
第三個例子委造,在類的靜態(tài)成員函數(shù)中使用類的非靜態(tài)成員
#include
class Point
{
public:
void init()
{
}
static void output()
{
printf("%d\n", m_x);
}
private:
int m_x;
};
void main()
{
Point pt;
pt.output();
}
編譯出錯:error C2597: illegal reference to data member 'Point::m_x' in a static member function
因為靜態(tài)成員函數(shù)屬于整個類,在類實例化對象之前就已經(jīng)分配空間了均驶,而類的非靜態(tài)成員必須在類實例化對象后才有內(nèi)存空間昏兆,所以這個調(diào)用就出錯了,就好比沒有聲明一個變量卻提前使用它一樣妇穴。
結(jié)論3:靜態(tài)成員函數(shù)中不能引用非靜態(tài)成員爬虱。
第四個例子隶债,在類的非靜態(tài)成員函數(shù)中使用類的靜態(tài)成員
class Point
{
public:
void init()
{
output();
}
static void output()
{
}
};
void main()
{
Point pt;
pt.output();
}
編譯通過。
結(jié)論4:類的非靜態(tài)成員函數(shù)可以調(diào)用用靜態(tài)成員函數(shù)跑筝,但反之不能死讹。
第五個例子,使用類的靜態(tài)成員變量
#include
class Point
{
public:
Point()
{
m_nPointCount++;
}
~Point()
{
m_nPointCount--;
}
static void output()
{
printf("%d\n", m_nPointCount);
}
private:
static int m_nPointCount;
};
void main()
{
Point pt;
pt.output();
}
按Ctrl+F7編譯無錯誤曲梗,按F7生成EXE程序時報鏈接錯誤
error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA)
這是因為類的靜態(tài)成員變量在使用前必須先初始化赞警。
在main()函數(shù)前加上int Point::m_nPointCount = 0;
再編譯鏈接無錯誤,運行程序?qū)⑤敵?虏两。
結(jié)論5:類的靜態(tài)成員變量必須先初始化再使用愧旦。
結(jié)合上面的五個例子,對類的靜態(tài)成員變量和成員函數(shù)作個總結(jié):
一定罢。靜態(tài)成員函數(shù)中不能調(diào)用非靜態(tài)成員笤虫。
二。非靜態(tài)成員函數(shù)中可以調(diào)用靜態(tài)成員祖凫。因為靜態(tài)成員屬于類本身琼蚯,在類的對象產(chǎn)生之前就已經(jīng)存在了,所以在非靜態(tài)成員函數(shù)中是可以調(diào)用靜態(tài)成員的蝙场。
三凌停。靜態(tài)成員變量使用前必須先初始化(如int MyClass::m_nNumber = 0;)粱年,否則會在linker時出錯售滤。
再給一個利用類的靜態(tài)成員變量和函數(shù)的例子以加深理解,這個例子建立一個學(xué)生類台诗,每個學(xué)生類的對象將組成一個雙向鏈表完箩,用一個靜態(tài)成員變量記錄這個雙向鏈表的表頭,一個靜態(tài)成員函數(shù)輸出這個雙向鏈表拉队。
#include
#include
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);
//建立雙向鏈表弊知,新數(shù)據(jù)從鏈表頭部插入。
this->next = m_head;
this->prev = NULL;
if (m_head != NULL)
m_head->prev = this;
m_head = this;
}
Student::~Student ()//析構(gòu)過程就是節(jié)點的脫離過程
{
if (this == m_head) //該節(jié)點就是頭節(jié)點粱快。
{
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();
}
程序?qū)⑤敵觯?/p>