程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 深刻解析C++編程中的靜態成員函數

深刻解析C++編程中的靜態成員函數

編輯:關於C++

深刻解析C++編程中的靜態成員函數。本站提示廣大學習愛好者:(深刻解析C++編程中的靜態成員函數)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻解析C++編程中的靜態成員函數正文


C++靜態成員函數

與數據成員相似,成員函數也能夠界說為靜態的,在類中聲明函數的後面加static就成了靜態成員函數。如

  static int volume( );


和靜態數據成員一樣,靜態成員函數是類的一部門,而不是對象的一部門。

假如要在類外挪用公用的靜態成員函數,要用類名和域運算符“::”。如

  Box::volume( );


現實上也許可經由過程對象名挪用靜態成員函數,如

  a.volume( );


但這其實不意味著此函數是屬於對象a的,而只是用a的類型罷了。

與靜態數據成員分歧,靜態成員函數的感化不是為了對象之間的溝通,而是為了能處置靜態數據成員。

我們曉得,當挪用一個對象的成員函數(非靜態成員函數)時,體系會把該對象的肇端地址賦給成員函數的this指針。而靜態成員函數其實不屬於某一對象,它與任何對象都有關,是以靜態成員函數沒有this指針。既然它沒有指向某一對象,就沒法對一個對象中的非靜態成員停止默許拜訪(即在援用數據成員時不指定對象名)。

可以說,靜態成員函數與非靜態成員函數的基本差別是:非靜態成員函數有this指針,而靜態成員函數沒有this指針。由此決議了靜態成員函數不克不及拜訪本類中的非靜態成員。

靜態成員函數可以直接援用本類中的靜態數據成員,由於靜態成員異樣是屬於類的,可以直接援用。在C++法式中,靜態成員函數重要用來拜訪靜態數據成員,而不拜訪非靜態成員。

假設在一個靜態成員函數中有以下語句:

  cout<<height<<endl; //若height已聲明為static,則援用本類中的靜態成員,正當
  cout<<width<<endl; //若width長短靜態數據成員,不正當


然則,其實不是相對不克不及援用本類中的非靜態成員,只是不克不及停止默許拜訪,由於沒法曉得應當去找哪一個對象。

假如必定要援用本類的非靜態成員,應當加對象名和成員運算符“.”。如

  cout<<a.width<<endl; //援用本類對象a中的非靜態成員


假定a已界說為Box類對象,且在以後感化域內有用,則此語句正當。

經由過程上面這個例子可以詳細懂得有關援用非靜態成員的詳細辦法。

[例] 靜態成員函數的運用。

#include <iostream>
using namespace std;
class Student          //界說Student類
{
public:
  Student(int n,int a,float s):num(n),age(a),score(s){ }   //界說結構函數
  void total( );
  static float average( );   //聲明靜態成員函數
private:
  int num;
  int age;
  float score;
  static float sum;      //靜態數據成員
  static int count;      //靜態數據成員
};
void Student::total( )           //界說非靜態成員函數
{
  sum+=score;              //累加總分
  count++;                //累計已統計的人數
}
float Student::average( )         //界說靜態成員函數
{
  return(sum/count);
}
float Student::sum=0;           //對靜態數據成員初始化
int Student::count=0;           //對靜態數據成員初始化
int main( )
{
  Student stud[3]={           //界說對象數組並初始化
   Student(1001,18,70),
   Student(1002,19,78),
   Student(1005,20,98)
  };
  int n;
  cout<<"please input the number of students:";
  cin>>n;                //輸出須要求後面若干邏輯學生的均勻成就
  for(int i=0;i<n;i++)         //挪用3次total函數
   stud[i].total( );
  cout<<"the average score of "<<n<<" students is "<<Student::average( )<<endl;
  //挪用靜態成員函數
  return 0;
}

運轉成果為:

please input the number of students:3↙
the average score of 3 students is 82.3333

關於靜態成員函數成員的幾點解釋:
在主函數中界說了stud對象數組,為了使法式簡潔,只界說它含3個元素,分離寄存3個先生的數據。法式的感化是先求用戶指定的n邏輯學生的總分,然後求均勻成就(n由用戶輸出)。
在Student類中界說了兩個靜態數據成員sum(總分)和count(累計須要統計的先生人數), 這是因為這兩個數據成員的值是須要停止累加的,它們其實不是只屬於某一個對象元素,而是由各對象元素同享的,可以看出: 它們的值是在赓續變更的,並且不管對哪一個對象元素而言,都是雷同的,並且一直不釋放內存空間。
total是私有的成員函數,其感化是將一個先生的成就累加到sum中。私有的成員函數可以援用本對象中的普通數據成員(非靜態數據成員),也能夠援用類中的靜態數據成員。score長短靜態數據成員,sum和count是靜態數據成員。
average是靜態成員函數,它可以直接援用公有的靜態數據成員(不用加類名或對象名), 函數前往成就的均勻值。
在main函數中,援用total函數要加對象名(今用對象數組元素名), 援用靜態成員函數average函數要用類名或對象名。
請思慮,假如不將average函數界說為靜態成員函數行不可?法式可否經由過程編譯?須要作甚麼修正?為何要用靜態成員函數?請剖析其來由。

C++ static靜態成員變量和靜態成員函數
普通情形下,假如有N個同類的對象,那末每個對象都分離有本身的成員變量,分歧對象的成員變量各自有值,互不相關。然則有時我們願望有某一個或幾個成員變量為一切對象共有,如許可以完成數據同享。

可使用全局變量來到達同享數據的目標。例如在一個法式文件中有多個函數,每個函數都可以轉變全局變量的值,全局變量的值為各函數同享。然則用全局變量的平安性得不到包管,因為在遍地都可以自在地修正全局變量的值,很有能夠有時掉誤,全局變量的值就被修正,招致法式的掉敗。是以在現實開辟中很少應用全局變量。

假如想在同類的多個對象之間完成數據同享,也不要用全局變量,那末可使用靜態成員變量。
static靜態成員變量

靜態成員變量是一種特別的成員變量,它以症結字 static 開首。例如:

class Student{
private:
  char *name;
  int age;
  float score;
  static int num; //將num界說為靜態成員變量
public:
  Student(char *, int, float);
  void say();
};

這段代碼聲清楚明了一個靜態成員變量 num,用來統計先生的人數。

static 成員變量屬於類,不屬於某個詳細的對象,這就意味著,即便創立多個對象,也只為 num 分派一分內存,一切對象應用的都是這分內存中的數據。當某個對象修正了 num,也會影響到其他對象。

static 成員變量必需先初始化能力應用,不然鏈接毛病。例如:

int Student::num; //初始化


也能夠在初始化時賦初值:

int Student::num = 10; //初始化同時賦值


初始化時可以不加 static,但必需要稀有據類型。被 private、protected、public 潤飾的 static 成員變量都可以用這類方法初始化。

留意:static 成員變量的內存空間既不是在聲明類時分派,也不是在創立對象時分派,而是在初始化時分派。

static 成員變量既可以經由過程對象來拜訪,也能夠經由過程類來拜訪。經由過程類來拜訪的情勢為:

類名::成員變量;


例如:

//經由過程類來拜訪
Student::num = 10;
//經由過程對象來拜訪
Student stu;
stu.num = 10;


這兩種方法是等效的。

留意:static 成員變量與對象有關,不占用對象的內存,而是在一切對象以外開拓內存,即便不創立對象也能夠拜訪。

上面來看一個完全的例子:

#include <iostream>
using namespace std;
class Student{
private:
  char *name;
  int age;
  float score;
  static int num; //將num界說為靜態成員變量
public:
  Student(char *, int, float);
  void say();
};
int Student::num = 0; //初始化靜態成員變量
Student::Student(char *name, int age, float score){
  this->name = name;
  this->age = age;
  this->score = score;
  num++;
}
void Student::say(){
  //在通俗成員函數中可以拜訪靜態成員變量
  cout<<name<<"的年紀是 "<<age<<",成就是 "<<score<<"(以後共"<<num<<"邏輯學生)"<<endl;
}
int main(){
  //應用匿名對象
  (new Student("小明", 15, 90))->say();
  (new Student("李磊", 16, 80))->say();
  (new Student("張華", 16, 99))->say();
  (new Student("王康", 14, 60))->say();
  return 0;
}

運轉成果:

小明的年紀是 15,成就是 90(以後共1邏輯學生)
李磊的年紀是 16,成就是 80(以後共2邏輯學生)
張華的年紀是 16,成就是 99(以後共3邏輯學生)
王康的年紀是 14,成就是 60(以後共4邏輯學生)

本例中將 num 聲明為靜態成員變量,每次創立對象時,會挪用結構函數,將 num 的值加 1。之所以應用匿名對象,是由於每次創立對象後只會應用它的 say 函數,不再停止其他操作。不外請留意,應用匿名對象有內存洩漏的風險。

關於靜態數據成員的幾點解釋:
1) 一個類中可以有一個或多個靜態成員變量,一切的對象都同享這些靜態成員變量,都可以援用它。

2) static 成員變量和通俗 static 變量一樣,編譯時在靜態數據辨別配內存,到法式停止時才釋放。這就意味著,static 成員變量不隨對象的創立而分派內存,也不隨對象的燒毀而釋放內存。而通俗成員變量在對象創立時分派內存,在對象燒毀時釋放內存。

3) 靜態成員變量必需初始化,並且只能在類體外停止。例如:

int Student::num = 10;


初始化時可以賦初值,也能夠不賦值。假如不賦值,那末會被默許初始化,普通是 0。靜態數據區的變量都有默許的初始值,而靜態數據區(堆區、棧區)的變量默許是渣滓值。

4) 靜態成員變量既可以經由過程對象名拜訪,也能夠經由過程類名拜訪,但要遵守 private、protected 和 public 症結字的拜訪權限限制。當經由過程對象名拜訪時,關於分歧的對象,拜訪的是統一分內存。
static靜態成員函數

在類中,static 除聲明靜態成員變量,還可以聲明靜態成員函數。通俗成員函數可以拜訪一切成員變量,而靜態成員函數只能拜訪靜態成員變量。

我們曉得,當挪用一個對象的成員函數(非靜態成員函數)時,體系會把以後對象的肇端地址賦給 this 指針。而靜態成員函數其實不屬於某一對象,它與任何對象都有關,是以靜態成員函數沒有 this 指針。既然它沒有指向某一對象,就沒法對該對象中的非靜態成員停止拜訪。

可以說,靜態成員函數與非靜態成員函數的基本差別是:非靜態成員函數有 this 指針,而靜態成員函數沒有 this 指針。由此決議了靜態成員函數不克不及拜訪本類中的非靜態成員。

靜態成員函數可以直接援用本類中的靜態數據成員,由於靜態成員異樣是屬於類的,可以直接援用。在C++法式中,靜態成員函數重要用來拜訪靜態數據成員,而不拜訪非靜態成員。

假如要在類外挪用 public 屬性的靜態成員函數,要用類名和域解析符“::”。如:

Student::getNum();

固然也能夠經由過程對象名挪用靜態成員函數,如:

stu.getNum();

上面是一個完全的例子,經由過程靜態成員函數取得先生的均勻成就:

#include <iostream>
using namespace std;
class Student{
private:
  char *name;
  int age;
  float score;
  static int num; //先生人數
  static float total; //總分
public:
  Student(char *, int, float);
  void say();
  static float getAverage(); //靜態成員函數,用來取得均勻成就
};
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<<",成就是 "<<score<<"(以後共"<<num<<"邏輯學生)"<<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<<"均勻成就為 "<<Student::getAverage()<<endl;
  
  return 0;
}

運轉成果:

小明的年紀是 15,成就是 90(以後共1邏輯學生)
李磊的年紀是 16,成就是 80(以後共2邏輯學生)
張華的年紀是 16,成就是 99(以後共3邏輯學生)
王康的年紀是 14,成就是 60(以後共4邏輯學生)
均勻成就為 82.25

下面的代碼中,將 num、total 聲明為靜態成員變量,將 getAverage 聲明為靜態成員函數。在 getAverage 函數中,只應用了 total、num 兩個靜態成員變量。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved