[轉(zhuǎn)]靜態(tài)成員數(shù)據(jù)和靜態(tài)成員函數(shù)
在沒有講述本章內(nèi)容之前如果我們想要在一個范圍內(nèi)共享某一個數(shù)據(jù),那么我們會設(shè)立全局對象,但面向?qū)ο蟮某绦蚴怯蓪ο髽?gòu)成的,我們?nèi)绾尾拍茉陬惙秶鷥?nèi)共享數(shù)據(jù)呢?
這個問題便是本章的重點:
聲明為static的類成員或者成員函數(shù)便能在類的范圍內(nèi)共同享,我們把這樣的成員稱做靜態(tài)成員和靜態(tài)成員函數(shù)。
下面我們用幾個實例來說明這個問題,類的成員需要保護,通常情況下為了不違背類的封裝特性,我們是把類成員設(shè)置為protected(保護狀態(tài))的,但是我們?yōu)榱撕喕a,使要說明的問題更為直觀,更容易理解,我們在此處都設(shè)置為public。
以下程序我們來做一個模擬訪問的例子,在程序中,每建立一個對象我們設(shè)置的類靜態(tài)成員變自動加一,代碼如下:
#include <iostream>
using namespace std;
class Internet
{
public:
??? Internet(char *name,char *address)
??? {
??????? strcpy(Internet::name,name);
??????? strcpy(Internet::address,address);
??????? count++;
??? }
??? static void Internet::Sc()//靜態(tài)成員函數(shù)
??? {
??????? cout<<count<<endl;
??? }
??? Internet &Rq();
public:
??? char name[20];
??? char address[20];
??? static int count;//這里如果寫成static int count=0;就是錯誤的
};
Internet& Internet::Rq()//返回引用的成員函數(shù)
{
??? return *this;
}
int Internet::count = 0;//靜態(tài)成員的初始化
void vist()
{
??? Internet a1("中國軟件開發(fā)實驗室","
www.cndev-lab.com
");
??? Internet a2("中國軟件開發(fā)實驗室","
www.cndev-lab.com
");
}
void fn(Internet &s)
{
??? cout<<s.Rq().count;
}
void main()
{
??? cout<<Internet::count<<endl;//靜態(tài)成員值的輸出
??? vist();
??? Internet::Sc();//靜態(tài)成員函數(shù)的調(diào)用
??? Internet b("中國軟件","
www.cnsoft.com
");
??? Internet::Sc();
??? fn(b);
??? cin.get();
}
上面代碼我們用了幾種常用的方式建立對象,當(dāng)建立新對象并調(diào)用其構(gòu)造函數(shù)的時候,靜態(tài)成員cout便運行加1操作,靜態(tài)成員的初始化應(yīng)該在主函數(shù)調(diào)用之前,并且不能在類的聲明中出現(xiàn),通過運行過程的觀察我們發(fā)現(xiàn),靜態(tài)成員count的狀態(tài)并不會隨著一個新的對象的新建而重新定義,盡而我們了解到類的靜態(tài)成員是屬于類的而不是屬于哪一個對象的,所以靜態(tài)成員的使用應(yīng)該是類名稱加域區(qū)分符加成員名稱的,在上面的代碼中就是Internet::count,雖然我們?nèi)匀豢梢允褂脤ο竺狱c操作符號加成員名稱的方式使用,但是不推薦的,靜態(tài)態(tài)類成員的特性就是屬于類而不專屬于某一個對象。
靜態(tài)成員函數(shù)的特性類似于靜態(tài)成員的使用,同樣與對象無關(guān),調(diào)用方法為類名稱加域區(qū)分符加成員函數(shù)名稱,在上面的代碼中就是Internet::Sc();,靜態(tài)成員函數(shù)由于與對象無關(guān)系,所以在其中是不能對類的普通成員進行直接操作的。
如果上面的 static void Internet::Sc()修改成為:
static void Internet::Sc()//靜態(tài)成員函數(shù)
{
??? cout<<name<<endl;//錯誤
??? cout<<count<<endl;
}
靜態(tài)成員函數(shù)與普通成員函數(shù)的差別就在于缺少this指針,沒有這個this指針自然也就無從知道name是哪一個對象的成員了。
根據(jù)類靜態(tài)成員的特性我們可以簡單歸納出幾點,靜態(tài)成員的使用范圍:
1.用來保存對象的個數(shù)。
2.作為一個標(biāo)記,標(biāo)記一些動作是否發(fā)生,比如:文件的打開狀態(tài),打印機的使用狀態(tài),等等。
3.存儲鏈表的第一個或者最后一個成員的內(nèi)存地址。
為了做一些必要的練習(xí),深入的掌握靜態(tài)對象的存在的意義,我們以前面的結(jié)構(gòu)體的教程為基礎(chǔ),用類的方式描述一個線性鏈表,用于存儲若干學(xué)生的姓名,代碼如下:
#include <iostream>
using namespace std;
class Student
{
public:
??? Student (char *name);
??? ~Student();
public:
??? char name[30];
??? Student *next;
??? static Student *point;
};
Student::Student (char *name)
{
??? strcpy(Student::name,name);
??? this->next=point;
??? point=this;
}
Student::~Student ()//析構(gòu)過程就是節(jié)點的脫離過程
{
??? cout<<"析構(gòu):"<<name<<endl;
??? if(point==this)
??? {
??????? point=this->next;
??????? cin.get();
??????? return;
??? }
??? for(Student *ps=point;ps;ps=ps->next)
??? {
??????? if(ps->next==this)
??????? {
??????? cout<<ps->next<<"|"<<this->next<<endl;
??????? ps->next=next;//=next也可以寫成this->next;
??????? cin.get();
??????? return;
??????? }
??? }
??? cin.get();
}
Student* Student::point=NULL;
void main()
{
??? Student *c = new Student("marry");
??? Student a("colin");
??? Student b("jamesji");
??? delete c;
??? Student *fp=Student::point;
??? while(fp!=NULL)
??? {
??????? cout<<fp->name<<endl;
??????? fp=fp->next;
??? }
??? cin.get();
}
從上面的代碼來看,原來單純結(jié)構(gòu)化編程需要的一個鏈表進入全局指針在這里被類的靜態(tài)成員指針?biāo)娲?類的靜態(tài)成員完全可以替代全局變量),這個例子的理解重點主要是要注意觀察類成員的析構(gòu)順序,通過對析構(gòu)順序的理解,使用析構(gòu)函數(shù)來進行節(jié)點的脫鏈操作。
靜態(tài)成員的提出是為了解決數(shù)據(jù)共享的問題。實現(xiàn)共享有許多方法,如:設(shè)置全局性的變量或?qū)ο笫且环N方法。但是,全局變量或?qū)ο笫怯芯窒扌缘摹_@一章里,我們主要講述類的靜態(tài)成員來實現(xiàn)數(shù)據(jù)的共享。
靜態(tài)數(shù)據(jù)成員
在類中,靜態(tài)成員可以實現(xiàn)多個對象之間的數(shù)據(jù)共享,并且使用靜態(tài)數(shù)據(jù)成員還不會破壞隱藏的原則,即保證了安全性。因此,靜態(tài)成員是類的所有對象中共享的成員,而不是某個對象的成員。
使用靜態(tài)數(shù)據(jù)成員可以節(jié)省內(nèi)存,因為它是所有對象所公有的,因此,對多個對象來說,靜態(tài)數(shù)據(jù)成員只存儲一處,供所有對象共用。靜態(tài)數(shù)據(jù)成員的值對每個對象都是一樣,但它的值是可以更新的。只要對靜態(tài)數(shù)據(jù)成員的值更新一次,保證所有對象存取更新后的相同的值,這樣可以提高時間效率。
靜態(tài)數(shù)據(jù)成員的使用方法和注意事項如下:
1、靜態(tài)數(shù)據(jù)成員在定義或說明時前面加關(guān)鍵字static。
2、靜態(tài)成員初始化與一般數(shù)據(jù)成員初始化不同。靜態(tài)數(shù)據(jù)成員初始化的格式如下:
<數(shù)據(jù)類型><類名>::<靜態(tài)數(shù)據(jù)成員名>=<值>
這表明:
????? (1) 初始化在類體外進行,而前面不加static,以免與一般靜態(tài)變量或?qū)ο笙嗷煜?/font>
(2) 初始化時不加該成員的訪問權(quán)限控制符private,public等。
(3) 初始化時使用作用域運算符來標(biāo)明它所屬類,因此,靜態(tài)數(shù)據(jù)成員是類的成員,而不是對象的成員。
3、靜態(tài)數(shù)據(jù)成員是靜態(tài)存儲的,它是靜態(tài)生存期,必須對它進行初始化。
4、引用靜態(tài)數(shù)據(jù)成員時,采用如下格式:
<類名>::<靜態(tài)成員名>
如果靜態(tài)數(shù)據(jù)成員的訪問權(quán)限允許的話(即public的成員),可在程序中,按上述格式來引用靜態(tài)數(shù)據(jù)成員。
下面舉一例子,說明靜態(tài)數(shù)據(jù)成員的應(yīng)用:
#include
class Myclass
{
public:
Myclass(int a, int b, int c);
void GetNumber();
void GetSum();
private:
int A, B, C;
static int Sum;
};
int Myclass::Sum = 0;
Myclass::Myclass(int a, int b, int c)
{
A = a;
B = b;
C = c;
Sum += A+B+C;
}
void Myclass::GetNumber()
{
cout<<"Number="< }
void Myclass::GetSum()
{
cout<<"Sum="< }
void main()
{
Myclass M(3, 7, 10),N(14, 9, 11);
M.GetNumber();
N.GetNumber();
M.GetSum();
N.GetSum();
}
從輸出結(jié)果可以看到Sum的值對M對象和對N對象都是相等的。這是因為在初始化M對象時,將M對象的三個int型數(shù)據(jù)成員的值求和后賦給了Sum,于是Sum保存了該值。在初始化N對象時,對將N對象的三個int型數(shù)據(jù)成員的值求和后又加到Sum已有的值上,于是Sum將保存另后的值。所以,不論是通過對象M還是通過對象N來引用的值都是一樣的,即為54。
靜態(tài)成員函數(shù)
靜態(tài)成員函數(shù)和靜態(tài)數(shù)據(jù)成員一樣,它們都屬于類的靜態(tài)成員,它們都不是對象成員。因此,對靜態(tài)成員的引用不需要用對象名。
在靜態(tài)成員函數(shù)的實現(xiàn)中不能直接引用類中說明的非靜態(tài)成員,可以引用類中說明的靜態(tài)成員。如果靜態(tài)成員函數(shù)中要引用非靜態(tài)成員時,可通過對象來引用。下面通過例子來說明這一點。
#include
class M
{
public:
M(int a) { A=a; B+=a;}
static void f1(M m);
private:
int A;
static int B;
};
void M::f1(M m)
{
cout<<"A="< cout<<"B="< }
int M::B=0;
void main()
{
M P(5),Q(10);
M::f1(P); file://調(diào)用時不用對象名
M::f1(Q);
}
讀者可以自行分析其結(jié)果。從中可看出,調(diào)用靜態(tài)成員函數(shù)使用如下格式:
<類名>::<靜態(tài)成員函數(shù)名>(<參數(shù)表>);
posted on 2006-07-31 02:54
Jerry Cat 閱讀(287)
評論(0) 編輯 收藏 引用