1. 程式人生 > >靜態成員(C++學習筆記 27)

靜態成員(C++學習筆記 27)

  • 靜態成員:為了實現一個類的多個物件之間的資料共享。
  • 靜態成員包括 靜態資料成員靜態函式成員。

一、靜態資料成員

  • 在一個類中若將一個數據成員說明為static,這種成員稱為靜態資料成員。 與一般的資料成員不同,無論建立多少個類的物件,都只有一個靜態資料成員的拷貝。從而實現了同一個類的不同物件之間的資料共享。
  • 定義靜態資料成員的格式:
    static 資料型別 資料成員名

注意:

1、靜態資料成員的定義與普通資料成員相似,但前面要加上 static 關鍵字。例如:

static int count;    //靜態資料成員,用於統計學生人數
static float sum;    //靜態資料成員,用於統計累加成績
static float ave;	 //靜態資料成員,用於統計平均成績

2、靜態資料成員的初始化與普通資料成員不同。靜態資料成員的初始化應在類外單獨進行,而且應在定義物件之前進行。
  一般在主函式 main 之前,類宣告之後的特殊地帶為它提供定義和初始化。

靜態資料成員初始化的格式如下(注意:這時在資料成員名的前面不加static):
資料型別 類名::靜態資料成員名=初始值;

例如:

int Student::count=0;
float Student::sum=0.0;
float Student::ave=0.0;

3、靜態資料成員屬於類(準確地說是屬於類物件的集合),而不像普通資料成員那樣屬於某一物件,因此可以使用 “ 類名:: ” 訪問

靜態的資料成員。

格式如下:
類名::靜態資料成員名

例如:

Student::count;
Student::sum;

4、公有的靜態資料成員可以在物件定義之前被訪問;物件定義後,可以通過物件進行訪問公有的靜態資料成員。靜態資料成員是類的公共資料成員,是物件的共享資料項。

用物件訪問靜態資料成員的格式如下:
物件名.靜態資料成員名;
物件指標->靜態資料成員名;

5、私有靜態資料成員不能再類外直接訪問,必須通過公有的成員函式訪問。

6、C++支援靜態資料成員的一個重要原因是可以不必使用全域性變數。依賴於全域性變數的類幾乎都是違反面向物件程式設計的封裝特性的。靜態資料成員主要用作

類的所有物件所公用的資料,如統計總數,平均數等。

例 1 :靜態資料成員的引例

char *a = new char[20]
new分配記憶體,這裡分配了20個位元組,然後返回首地址給a
即a可以看做一個20位元組的字元陣列,即字串
參考: https://blog.csdn.net/aaqian1/article/details/83717529

#include<iostream>
#include<string.h>
using namespace std;
class Student{
	public:
		Student(char *name1,char *stu_no1,float score1);  //宣告建構函式
		~Student();   //宣告解構函式 
		void show();  //輸出姓名、學號和成績 
		void show_count_sum_ave();  //輸出學生人數和平均成績 
	private:
		char *name;  //學生姓名
		char *stu_no;  //學生學號
		float score;  //學生成績
		int count;  //學生人數
		float sum;  //累加成績
		float ave;  //平均成績 
};
Student::Student(char *name1,char *stu_no1,float score1){  //定義建構函式 
	name=new char[strlen(name1)+1];  //為了最後的'\0'留下位置 
	strcpy(name,name1);
	stu_no=new char[strlen(stu_no1)+1];
	strcpy(stu_no,stu_no1);
	score=score1;
	++count;  //累加學生人數
	sum=sum+score;  //累加成績
	ave=sum/count;   //計算平均成績 

}
Student::~Student(){
	delete []name;
	delete []stu_no;
	--count;
	sum=sum-score;
} 
void Student::show(){
	cout<<"\n姓名:"<<name;
	cout<<"\n學號:"<<stu_no;
	cout<<"\n成績:"<<score;
}
void Student::show_count_sum_ave(){
	cout<<"\n學生人數:"<<count;
	cout<<"\n平均成績:"<<ave;
}
int main(){
	Student stu1("李明","01",90);  //建立第 1 個學生物件stu1
	stu1.show();
	stu1.show_count_sum_ave();
	cout<<"\n------------------\n";
	Student stu2("王曉紅","02",88);  //建立第 2 個學生物件stu2
	stu2.show();
	stu2.show_count_sum_ave();
	cout<<"\n------------------\n";
	Student stu3("吳曉剛","03",90);  //建立第 1 個學生物件stu1
	stu3.show();
	stu3.show_count_sum_ave();
	return 0; 
}

這個是錯誤的,因為一個學生物件的count,sum和ave僅僅屬於這個學生物件,而不是所有學生物件所共享的,因此它們不能表示所有學生的人數、累加成績和平均成績。

例 2 :靜態資料成員的使用

#include<iostream>
#include<string.h>
using namespace std;
class Student{
	public:
		Student(char *name1,char *stu_no1,float score1);  //宣告建構函式
		~Student();   //宣告解構函式 
		void show();  //輸出姓名、學號和成績 
		void show_count_sum_ave();  //輸出學生人數和平均成績 
	private:
		char *name;  //學生姓名
		char *stu_no;  //學生學號
		float score;  //學生成績
		static int count;  //靜態成員函式,學生人數
		static float sum;  //靜態成員函式,累加成績
		static float ave;  //靜態成員函式,平均成績 
};
Student::Student(char *name1,char *stu_no1,float score1){  //定義建構函式 
	name=new char[strlen(name1)+1];  //為了最後的'\0'留下位置 
	strcpy(name,name1);
	stu_no=new char[strlen(stu_no1)+1];
	strcpy(stu_no,stu_no1);
	score=score1;
	++count;  //累加學生人數
	sum=sum+score;  //累加成績
	ave=sum/count;   //計算平均成績 

}
Student::~Student(){
	delete []name;
	delete []stu_no;
	--count;
	sum=sum-score;
} 
void Student::show(){
	cout<<"\n姓名:"<<name;
	cout<<"\n學號:"<<stu_no;
	cout<<"\n成績:"<<score;
}
void Student::show_count_sum_ave(){
	cout<<"\n學生人數:"<<count;
	cout<<"\n平均成績:"<<ave;
}
int Student::count=0;  //靜態資料成員count初始化
float Student::sum=0.0;  //靜態資料成員sum初始化
float Student::ave=0.0;  //靜態資料成員ave初始化
int main(){
	Student stu1("李明","01",90);  //建立第 1 個學生物件stu1
	stu1.show();
	stu1.show_count_sum_ave();
	cout<<"\n------------------\n";
	Student stu2("王曉紅","02",88);  //建立第 2 個學生物件stu2
	stu2.show();
	stu2.show_count_sum_ave();
	cout<<"\n------------------\n";
	Student stu3("吳曉剛","03",90);  //建立第 1 個學生物件stu1
	stu3.show();
	stu3.show_count_sum_ave();
	return 0; 
}

例 3:公有靜態成員函式的訪問

#include<iostream>
using namespace std;
class Myclass{
	public:
		static int i;
		int geti(){
			return i;
		}
};
int Myclass::i=0;  //靜態資料成員初始化,不必在前面加static
int main(){
	Myclass::i=200;
	Myclass ob1,ob2;
	cout<<"ob1.i="<<ob1.geti()<<endl;
	cout<<"ob2.i="<<ob2.geti()<<endl;
	ob1.i=300;
	cout<<"ob1.i="<<ob1.geti()<<endl;
	cout<<"ob2.i="<<ob2.geti()<<endl;
	return 0;
} 

執行結果如下:
在這裡插入圖片描述
所以,靜態資料成員也是類的公共資料成員,是物件的共享資料項。

二、靜態成員函式

  • 在類定義中,前面有static說明的成員函式稱為靜態成員函式。靜態成員函式屬於整個類,是該類所有物件共享的成員函式,而不屬於類中的某個物件。
  • 定義靜態成員函式的格式:
    static 返回型別 靜態成員函式名(引數表);
  • 與靜態資料成員類似,呼叫公有靜態成員函式的一般格式有如下幾種:
    類名::靜態成員函式名(實參表)
    物件.靜態成員函式名(實參表)
    物件指標->靜態成員函式名(實參表)

注意:

1、一般情況下,靜態函式成員主要用來訪問靜態資料成員。當它與靜態資料成員一起使用時,達到了對同一類中物件之間資料共享的目的。

2、私有靜態成員函式不能做類外部的函式和物件訪問。

3、使用靜態成員函式的一個原因是,可以用它在建立任何物件之前呼叫靜態成員函式,以處理靜態資料成員,這是普通成員函式不能實現的功能。例如:

int main(){
	Small_cat::total_disp();  //可以用它在建立任何物件之前呼叫靜態成員函式
	Small_cat w1(0.2),w2(0.3),w3(0.4);
	·
	·
	·
	return 0;
}

4、編譯系統將靜態成員函式限定為內部連線。即與現行檔案相連線的其他檔案中的同名函式不會與該函式發生衝突,維護了該函式使用的安全性。

5、靜態成員函式是類的一部分,而不是物件的一部分。如果要在類外呼叫公有的靜態成員函式,使用如下格式較好:
類名::靜態成員函式名
如果定義了這個類的物件(例如w1),使用 物件名.靜態成員函式名 也是正確的。

6、靜態成員函式與非靜態成員函式的重要區別是:非靜態成員函式有this指標,而靜態成員函式沒有this指標。
  一般而言,靜態成員函式不訪問類中的非靜態成員,可以直接訪問本類中的靜態資料成員。
  若確實需要訪問非靜態資料成員,靜態成員函式只能通過物件名(或物件指標,物件引用)訪問該物件的非靜態成員。

例 4 :靜態成員函式訪問靜態資料成員

#include<iostream>
using namespace std;
class Small_cat{
	public:
		Small_cat(double w);  //宣告建構函式
		void display();   //宣告非靜態成員函式
		static void total_disp();  //宣告靜態成員函式
	private:
		double weight;  //普通資料成員,表示一隻小貓的重量 
		static double total_weight;   //靜態資料成員,用來累計小貓的重量
		static double total_number;	  //靜態資料成員,用來累計小貓的只數 
};
Small_cat::Small_cat(double w){	//定義建構函式
	weight=w;  
	total_weight+=w;	//累加小貓的重量
	total_number++;		//累加小貓的只數 
} 
void Small_cat::display(){	//定義非靜態成員函式 
	cout<<"這隻小貓的重量是:"<<weight<<"千克\n";   //顯示每隻小貓的重量 
}
void Small_cat::total_disp()	//定義靜態成員函式,顯示小貓的只數和總重量
//在這裡不要使用 static 字首 
{
	cout<<total_number<<"只小貓的重量是:";
	cout<<total_weight<<"千克"<<endl;	
} 

//靜態成員函式初始化 
double Small_cat::total_weight=0;  
double Small_cat::total_number=0;

int main(){
	Small_cat w1(0.5),w2(0.4),w3(0.3);
	w1.display();	//呼叫非靜態成員函式,顯示第 1 只小貓的重量
	w2.display();	//呼叫非靜態成員函式,顯示第 2 只小貓的重量
	w3.display();	//呼叫非靜態成員函式,顯示第 3 只小貓的重量
	Small_cat::total_disp();	//呼叫靜態成員函式,顯示小貓的只數和總重量
	return 0; 
}

執行結果:
在這裡插入圖片描述

例 4 :靜態成員函式訪問非靜態資料成員

#include<iostream>
using namespace std;
class Small_cat{
	public:
		Small_cat(double w);  //宣告建構函式
		static void display(Small_cat &w);   //宣告靜態成員函式
		static void total_disp();  //宣告靜態成員函式
	private:
		double weight;  //普通資料成員,表示一隻小貓的重量 
		static double total_weight;   //靜態資料成員,用來累計小貓的重量
		static double total_number;	  //靜態資料成員,用來累計小貓的只數 
};
Small_cat::Small_cat(double w){	//定義建構函式
	weight=w;  
	total_weight+=w;	//累加小貓的重量
	total_number++;		//累加小貓的只數 
} 
void Small_cat::display(Small_cat &w){	//定義靜態成員函式, 將物件的引用作為引數,顯示每隻小貓的重量 
	cout<<"這隻小貓的重量是:"<<w.weight<<"千克\n";   //顯示每隻小貓的重量 
}
void Small_cat::total_disp()	//定義靜態成員函式,顯示小貓的只數和總重量
//在這裡不要使用 static 字首 
{
	cout<<total_number<<"只小貓的重量是:";
	cout<<total_weight<<"千克"<<endl;	
} 

//靜態成員函式初始化 
double Small_cat::total_weight=0;  
double Small_cat::total_number=0;

int main(){
	Small_cat w1(0.5),w2(0.4),w3(0.3);
	w1.display(w1);	//呼叫非靜態成員函式,顯示第 1 只小貓的重量
	w2.display(w2);	//呼叫非靜態成員函式,顯示第 2 只小貓的重量
	w3.display(w3);	//呼叫非靜態成員函式,顯示第 3 只小貓的重量
	Small_cat::total_disp();	//呼叫靜態成員函式,顯示小貓的只數和總重量
	return 0; 
}