深入解析C++編程中的靜態(tài)成員函數(shù)
C++靜態(tài)成員函數(shù)
與數(shù)據(jù)成員類(lèi)似,成員函數(shù)也可以定義為靜態(tài)的,在類(lèi)中聲明函數(shù)的前面加static就成了靜態(tài)成員函數(shù)。如
static int volume( );
和靜態(tài)數(shù)據(jù)成員一樣,靜態(tài)成員函數(shù)是類(lèi)的一部分,而不是對(duì)象的一部分。
如果要在類(lèi)外調(diào)用公用的靜態(tài)成員函數(shù),要用類(lèi)名和域運(yùn)算符“::”。如
Box::volume( );
實(shí)際上也允許通過(guò)對(duì)象名調(diào)用靜態(tài)成員函數(shù),如
a.volume( );
但這并不意味著此函數(shù)是屬于對(duì)象a的,而只是用a的類(lèi)型而已。
與靜態(tài)數(shù)據(jù)成員不同,靜態(tài)成員函數(shù)的作用不是為了對(duì)象之間的溝通,而是為了能處理靜態(tài)數(shù)據(jù)成員。
我們知道,當(dāng)調(diào)用一個(gè)對(duì)象的成員函數(shù)(非靜態(tài)成員函數(shù))時(shí),系統(tǒng)會(huì)把該對(duì)象的起始地址賦給成員函數(shù)的this指針。而靜態(tài)成員函數(shù)并不屬于某一對(duì)象,它與任何對(duì)象都無(wú)關(guān),因此靜態(tài)成員函數(shù)沒(méi)有this指針。既然它沒(méi)有指向某一對(duì)象,就無(wú)法對(duì)一個(gè)對(duì)象中的非靜態(tài)成員進(jìn)行默認(rèn)訪問(wèn)(即在引用數(shù)據(jù)成員時(shí)不指定對(duì)象名)。
可以說(shuō),靜態(tài)成員函數(shù)與非靜態(tài)成員函數(shù)的根本區(qū)別是:非靜態(tài)成員函數(shù)有this指針,而靜態(tài)成員函數(shù)沒(méi)有this指針。由此決定了靜態(tài)成員函數(shù)不能訪問(wèn)本類(lèi)中的非靜態(tài)成員。
靜態(tài)成員函數(shù)可以直接引用本類(lèi)中的靜態(tài)數(shù)據(jù)成員,因?yàn)殪o態(tài)成員同樣是屬于類(lèi)的,可以直接引用。在C++程序中,靜態(tài)成員函數(shù)主要用來(lái)訪問(wèn)靜態(tài)數(shù)據(jù)成員,而不訪問(wèn)非靜態(tài)成員。
假如在一個(gè)靜態(tài)成員函數(shù)中有以下語(yǔ)句:
cout<<height<<endl; //若height已聲明為static,則引用本類(lèi)中的靜態(tài)成員,合法 cout<<width<<endl; //若width是非靜態(tài)數(shù)據(jù)成員,不合法
但是,并不是絕對(duì)不能引用本類(lèi)中的非靜態(tài)成員,只是不能進(jìn)行默認(rèn)訪問(wèn),因?yàn)闊o(wú)法知道應(yīng)該去找哪個(gè)對(duì)象。
如果一定要引用本類(lèi)的非靜態(tài)成員,應(yīng)該加對(duì)象名和成員運(yùn)算符“.”。如
cout<<a.width<<endl; //引用本類(lèi)對(duì)象a中的非靜態(tài)成員
假設(shè)a已定義為Box類(lèi)對(duì)象,且在當(dāng)前作用域內(nèi)有效,則此語(yǔ)句合法。
通過(guò)下面這個(gè)例子可以具體了解有關(guān)引用非靜態(tài)成員的具體方法。
[例] 靜態(tài)成員函數(shù)的應(yīng)用。
#include <iostream>
using namespace std;
class Student //定義Student類(lèi)
{
public:
Student(int n,int a,float s):num(n),age(a),score(s){ } //定義構(gòu)造函數(shù)
void total( );
static float average( ); //聲明靜態(tài)成員函數(shù)
private:
int num;
int age;
float score;
static float sum; //靜態(tài)數(shù)據(jù)成員
static int count; //靜態(tài)數(shù)據(jù)成員
};
void Student::total( ) //定義非靜態(tài)成員函數(shù)
{
sum+=score; //累加總分
count++; //累計(jì)已統(tǒng)計(jì)的人數(shù)
}
float Student::average( ) //定義靜態(tài)成員函數(shù)
{
return(sum/count);
}
float Student::sum=0; //對(duì)靜態(tài)數(shù)據(jù)成員初始化
int Student::count=0; //對(duì)靜態(tài)數(shù)據(jù)成員初始化
int main( )
{
Student stud[3]={ //定義對(duì)象數(shù)組并初始化
Student(1001,18,70),
Student(1002,19,78),
Student(1005,20,98)
};
int n;
cout<<"please input the number of students:";
cin>>n; //輸入需要求前面多少名學(xué)生的平均成績(jī)
for(int i=0;i<n;i++) //調(diào)用3次total函數(shù)
stud[i].total( );
cout<<"the average score of "<<n<<" students is "<<Student::average( )<<endl;
//調(diào)用靜態(tài)成員函數(shù)
return 0;
}
運(yùn)行結(jié)果為:
please input the number of students:3↙ the average score of 3 students is 82.3333
關(guān)于靜態(tài)成員函數(shù)成員的幾點(diǎn)說(shuō)明:
在主函數(shù)中定義了stud對(duì)象數(shù)組,為了使程序簡(jiǎn)練,只定義它含3個(gè)元素,分別存放3個(gè)學(xué)生的數(shù)據(jù)。程序的作用是先求用戶指定的n名學(xué)生的總分,然后求平均成績(jī)(n由用戶輸入)。
在Student類(lèi)中定義了兩個(gè)靜態(tài)數(shù)據(jù)成員sum(總分)和count(累計(jì)需要統(tǒng)計(jì)的學(xué)生人數(shù)), 這是由于這兩個(gè)數(shù)據(jù)成員的值是需要進(jìn)行累加的,它們并不是只屬于某一個(gè)對(duì)象元素,而是由各對(duì)象元素共享的,可以看出: 它們的值是在不斷變化的,而且無(wú)論對(duì)哪個(gè)對(duì)象元素而言,都是相同的,而且始終不釋放內(nèi)存空間。
total是公有的成員函數(shù),其作用是將一個(gè)學(xué)生的成績(jī)累加到sum中。公有的成員函數(shù)可以引用本對(duì)象中的一般數(shù)據(jù)成員(非靜態(tài)數(shù)據(jù)成員),也可以引用類(lèi)中的靜態(tài)數(shù)據(jù)成員。score是非靜態(tài)數(shù)據(jù)成員,sum和count是靜態(tài)數(shù)據(jù)成員。
average是靜態(tài)成員函數(shù),它可以直接引用私有的靜態(tài)數(shù)據(jù)成員(不必加類(lèi)名或?qū)ο竺?, 函數(shù)返回成績(jī)的平均值。
在main函數(shù)中,引用total函數(shù)要加對(duì)象名(今用對(duì)象數(shù)組元素名), 引用靜態(tài)成員函數(shù)average函數(shù)要用類(lèi)名或?qū)ο竺?br />
請(qǐng)思考,如果不將average函數(shù)定義為靜態(tài)成員函數(shù)行不行?程序能否通過(guò)編譯?需要作什么修改?為什么要用靜態(tài)成員函數(shù)?請(qǐng)分析其理由。
C++ static靜態(tài)成員變量和靜態(tài)成員函數(shù)
一般情況下,如果有N個(gè)同類(lèi)的對(duì)象,那么每一個(gè)對(duì)象都分別有自己的成員變量,不同對(duì)象的成員變量各自有值,互不相干。但是有時(shí)我們希望有某一個(gè)或幾個(gè)成員變量為所有對(duì)象共有,這樣可以實(shí)現(xiàn)數(shù)據(jù)共享。
可以使用全局變量來(lái)達(dá)到共享數(shù)據(jù)的目的。例如在一個(gè)程序文件中有多個(gè)函數(shù),每一個(gè)函數(shù)都可以改變?nèi)肿兞康闹?,全局變量的值為各函?shù)共享。但是用全局變量的安全性得不到保證,由于在各處都可以自由地修改全局變量的值,很有可能偶然失誤,全局變量的值就被修改,導(dǎo)致程序的失敗。因此在實(shí)際開(kāi)發(fā)中很少使用全局變量。
如果想在同類(lèi)的多個(gè)對(duì)象之間實(shí)現(xiàn)數(shù)據(jù)共享,也不要用全局變量,那么可以使用靜態(tài)成員變量。
static靜態(tài)成員變量
靜態(tài)成員變量是一種特殊的成員變量,它以關(guān)鍵字 static 開(kāi)頭。例如:
class Student{
private:
char *name;
int age;
float score;
static int num; //將num定義為靜態(tài)成員變量
public:
Student(char *, int, float);
void say();
};
這段代碼聲明了一個(gè)靜態(tài)成員變量 num,用來(lái)統(tǒng)計(jì)學(xué)生的人數(shù)。
static 成員變量屬于類(lèi),不屬于某個(gè)具體的對(duì)象,這就意味著,即使創(chuàng)建多個(gè)對(duì)象,也只為 num 分配一份內(nèi)存,所有對(duì)象使用的都是這份內(nèi)存中的數(shù)據(jù)。當(dāng)某個(gè)對(duì)象修改了 num,也會(huì)影響到其他對(duì)象。
static 成員變量必須先初始化才能使用,否則鏈接錯(cuò)誤。例如:
int Student::num; //初始化
也可以在初始化時(shí)賦初值:
int Student::num = 10; //初始化同時(shí)賦值
初始化時(shí)可以不加 static,但必須要有數(shù)據(jù)類(lèi)型。被 private、protected、public 修飾的 static 成員變量都可以用這種方式初始化。
注意:static 成員變量的內(nèi)存空間既不是在聲明類(lèi)時(shí)分配,也不是在創(chuàng)建對(duì)象時(shí)分配,而是在初始化時(shí)分配。
static 成員變量既可以通過(guò)對(duì)象來(lái)訪問(wèn),也可以通過(guò)類(lèi)來(lái)訪問(wèn)。通過(guò)類(lèi)來(lái)訪問(wèn)的形式為:
類(lèi)名::成員變量;
例如:
//通過(guò)類(lèi)來(lái)訪問(wèn) Student::num = 10; //通過(guò)對(duì)象來(lái)訪問(wèn) Student stu; stu.num = 10;
這兩種方式是等效的。
注意:static 成員變量與對(duì)象無(wú)關(guān),不占用對(duì)象的內(nèi)存,而是在所有對(duì)象之外開(kāi)辟內(nèi)存,即使不創(chuàng)建對(duì)象也可以訪問(wèn)。
下面來(lái)看一個(gè)完整的例子:
#include <iostream>
using namespace std;
class Student{
private:
char *name;
int age;
float score;
static int num; //將num定義為靜態(tài)成員變量
public:
Student(char *, int, float);
void say();
};
int Student::num = 0; //初始化靜態(tài)成員變量
Student::Student(char *name, int age, float score){
this->name = name;
this->age = age;
this->score = score;
num++;
}
void Student::say(){
//在普通成員函數(shù)中可以訪問(wèn)靜態(tài)成員變量
cout<<name<<"的年齡是 "<<age<<",成績(jī)是 "<<score<<"(當(dāng)前共"<<num<<"名學(xué)生)"<<endl;
}
int main(){
//使用匿名對(duì)象
(new Student("小明", 15, 90))->say();
(new Student("李磊", 16, 80))->say();
(new Student("張華", 16, 99))->say();
(new Student("王康", 14, 60))->say();
return 0;
}
運(yùn)行結(jié)果:
小明的年齡是 15,成績(jī)是 90(當(dāng)前共1名學(xué)生) 李磊的年齡是 16,成績(jī)是 80(當(dāng)前共2名學(xué)生) 張華的年齡是 16,成績(jī)是 99(當(dāng)前共3名學(xué)生) 王康的年齡是 14,成績(jī)是 60(當(dāng)前共4名學(xué)生)
本例中將 num 聲明為靜態(tài)成員變量,每次創(chuàng)建對(duì)象時(shí),會(huì)調(diào)用構(gòu)造函數(shù),將 num 的值加 1。之所以使用匿名對(duì)象,是因?yàn)槊看蝿?chuàng)建對(duì)象后只會(huì)使用它的 say 函數(shù),不再進(jìn)行其他操作。不過(guò)請(qǐng)注意,使用匿名對(duì)象有內(nèi)存泄露的風(fēng)險(xiǎn)。
關(guān)于靜態(tài)數(shù)據(jù)成員的幾點(diǎn)說(shuō)明:
1) 一個(gè)類(lèi)中可以有一個(gè)或多個(gè)靜態(tài)成員變量,所有的對(duì)象都共享這些靜態(tài)成員變量,都可以引用它。
2) static 成員變量和普通 static 變量一樣,編譯時(shí)在靜態(tài)數(shù)據(jù)區(qū)分配內(nèi)存,到程序結(jié)束時(shí)才釋放。這就意味著,static 成員變量不隨對(duì)象的創(chuàng)建而分配內(nèi)存,也不隨對(duì)象的銷(xiāo)毀而釋放內(nèi)存。而普通成員變量在對(duì)象創(chuàng)建時(shí)分配內(nèi)存,在對(duì)象銷(xiāo)毀時(shí)釋放內(nèi)存。
3) 靜態(tài)成員變量必須初始化,而且只能在類(lèi)體外進(jìn)行。例如:
int Student::num = 10;
初始化時(shí)可以賦初值,也可以不賦值。如果不賦值,那么會(huì)被默認(rèn)初始化,一般是 0。靜態(tài)數(shù)據(jù)區(qū)的變量都有默認(rèn)的初始值,而動(dòng)態(tài)數(shù)據(jù)區(qū)(堆區(qū)、棧區(qū))的變量默認(rèn)是垃圾值。
4) 靜態(tài)成員變量既可以通過(guò)對(duì)象名訪問(wèn),也可以通過(guò)類(lèi)名訪問(wèn),但要遵循 private、protected 和 public 關(guān)鍵字的訪問(wèn)權(quán)限限制。當(dāng)通過(guò)對(duì)象名訪問(wèn)時(shí),對(duì)于不同的對(duì)象,訪問(wèn)的是同一份內(nèi)存。
static靜態(tài)成員函數(shù)
在類(lèi)中,static 除了聲明靜態(tài)成員變量,還可以聲明靜態(tài)成員函數(shù)。普通成員函數(shù)可以訪問(wèn)所有成員變量,而靜態(tài)成員函數(shù)只能訪問(wèn)靜態(tài)成員變量。
我們知道,當(dāng)調(diào)用一個(gè)對(duì)象的成員函數(shù)(非靜態(tài)成員函數(shù))時(shí),系統(tǒng)會(huì)把當(dāng)前對(duì)象的起始地址賦給 this 指針。而靜態(tài)成員函數(shù)并不屬于某一對(duì)象,它與任何對(duì)象都無(wú)關(guān),因此靜態(tài)成員函數(shù)沒(méi)有 this 指針。既然它沒(méi)有指向某一對(duì)象,就無(wú)法對(duì)該對(duì)象中的非靜態(tài)成員進(jìn)行訪問(wèn)。
可以說(shuō),靜態(tài)成員函數(shù)與非靜態(tài)成員函數(shù)的根本區(qū)別是:非靜態(tài)成員函數(shù)有 this 指針,而靜態(tài)成員函數(shù)沒(méi)有 this 指針。由此決定了靜態(tài)成員函數(shù)不能訪問(wèn)本類(lèi)中的非靜態(tài)成員。
靜態(tài)成員函數(shù)可以直接引用本類(lèi)中的靜態(tài)數(shù)據(jù)成員,因?yàn)殪o態(tài)成員同樣是屬于類(lèi)的,可以直接引用。在C++程序中,靜態(tài)成員函數(shù)主要用來(lái)訪問(wèn)靜態(tài)數(shù)據(jù)成員,而不訪問(wèn)非靜態(tài)成員。
如果要在類(lèi)外調(diào)用 public 屬性的靜態(tài)成員函數(shù),要用類(lèi)名和域解析符“::”。如:
Student::getNum();
當(dāng)然也可以通過(guò)對(duì)象名調(diào)用靜態(tài)成員函數(shù),如:
stu.getNum();
下面是一個(gè)完整的例子,通過(guò)靜態(tài)成員函數(shù)獲得學(xué)生的平均成績(jī):
#include <iostream>
using namespace std;
class Student{
private:
char *name;
int age;
float score;
static int num; //學(xué)生人數(shù)
static float total; //總分
public:
Student(char *, int, float);
void say();
static float getAverage(); //靜態(tài)成員函數(shù),用來(lái)獲得平均成績(jī)
};
int Student::num = 0;
float Student::total = 0;
Student::Student(char *name, int age, float score){
this->name = name;
this->age = age;
this->score = score;
num++;
total += score;
}
void Student::say(){
cout<<name<<"的年齡是 "<<age<<",成績(jī)是 "<<score<<"(當(dāng)前共"<<num<<"名學(xué)生)"<<endl;
}
float Student::getAverage(){
return total / num;
}
int main(){
(new Student("小明", 15, 90))->say();
(new Student("李磊", 16, 80))->say();
(new Student("張華", 16, 99))->say();
(new Student("王康", 14, 60))->say();
cout<<"平均成績(jī)?yōu)?"<<Student::getAverage()<<endl;
return 0;
}
運(yùn)行結(jié)果:
小明的年齡是 15,成績(jī)是 90(當(dāng)前共1名學(xué)生) 李磊的年齡是 16,成績(jī)是 80(當(dāng)前共2名學(xué)生) 張華的年齡是 16,成績(jī)是 99(當(dāng)前共3名學(xué)生) 王康的年齡是 14,成績(jī)是 60(當(dāng)前共4名學(xué)生) 平均成績(jī)?yōu)?82.25
上面的代碼中,將 num、total 聲明為靜態(tài)成員變量,將 getAverage 聲明為靜態(tài)成員函數(shù)。在 getAverage 函數(shù)中,只使用了 total、num 兩個(gè)靜態(tài)成員變量。
上一篇:詳解C++編程中類(lèi)的成員變量和成員函數(shù)的相關(guān)知識(shí)
欄 目:C語(yǔ)言
本文標(biāo)題:深入解析C++編程中的靜態(tài)成員函數(shù)
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/2714.html
您可能感興趣的文章
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 01-10深入理解約瑟夫環(huán)的數(shù)學(xué)優(yōu)化方法
- 01-10深入二叉樹(shù)兩個(gè)結(jié)點(diǎn)的最低共同父結(jié)點(diǎn)的詳解
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)- 解析最少換車(chē)次數(shù)的問(wèn)題詳解
- 01-10深入理解C++中常見(jiàn)的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10深入Main函數(shù)中的參數(shù)argc,argv的使用詳解
- 01-10深入第K大數(shù)問(wèn)題以及算法概要的詳解
- 01-10深入解析最長(zhǎng)公共子串
- 01-10c++中inline的用法分析


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改


