static 成員


對於每一個基於相同類別所產生的物件而言,它們會擁有各自的資料成員,然而在某些時候,您會想要這些物件擁有相同的資料成員,舉個例子來說,在Ball類 別中,您打算使用到圓周率PI這個資料,因為對於任一個Ball的實例而言,圓周率都是相同的,您不需要讓不同的Ball實例擁有各自的圓周率資料成員。

您可以將PI資料成員宣告為"static",被宣告為"static"的資料成員,又稱「靜態資料成員」,靜態成員是屬於類別所擁有,而不是個別的物 件,您可以將靜態成員視為每個物件實例所共享的資料成員。要宣告靜態資料成員,只要在宣告資料成員時加上"static"關鍵字就可以了,例如:
  • Ball.h
#include <string>
using namespace std;

class Ball {
public:
// 宣告靜態成員
static double PI;
// const 靜態成員可以在類別定義中初始化
// static const double PI = 3.14159;

Ball();
Ball(double, const char*);
Ball(double, string&);

double radius() {
return _radius;
}

string& name() {
return _name;
}

void radius(double radius) {
_radius = radius;
}

void name(const char *name) {
_name = name;
}

void name(string& name) {
_name = name;
}

double volumn() {
return (4 / 3 * PI * _radius * _radius * _radius);
}

private:
double _radius; // 半徑
string _name; // 名稱
};

  • Ball.cpp
#include <string>
#include "Ball.h"
using namespace std;

// 非const靜態成員要在類別定義外初始化
double Ball::PI = 3.14159;

// 預設建構函式
Ball::Ball() {
_radius = 0.0;
_name = "noname ball";
}

Ball::Ball(double radius, const char *name) {
_radius = radius;
_name = name;
}

Ball::Ball(double radius, string &name) {
_radius = radius;
_name = name;
}


非const的static成員要在類別定義區塊之外初始化,靜態成員屬 於類別所擁有,可以在 不使用名稱參考下,直接使用類別名稱加上
::運算子來存取靜態資料成員,不過靜態資料成員同樣遵守"public""protected""private"的存取限制,所以若 您要直接存取靜態資料成員,必須注意它的權限,例如必須設定為"public"成員的話就可以如下存取:

  • main.cpp
#include <iostream>
#include "Ball.h"
using namespace std;

int main() {
cout << Ball::PI
<< endl;

return 0;
}

執行結果:
3.14159

雖然您也可以在宣告物件之後,透過物件名稱加上'.'運算子來存取靜態資料成員,但是這個方式並不被鼓勵,通常建議使用類別名稱加上'::'運算子來存取, 一方面也可以避免與非靜態資料成員混淆,例如下面的方式是不被鼓勵的:
Ball ball;
cout << ball.PI << endl;

與靜態資料成員類似的,您也可以宣告函式成員為"static"方法,又稱「靜態函式」,被宣告為靜態的函式通常是作為工具函式,例如在Ball類別上增 加一個角度轉徑度的函式toRadian():
  • Ball.h
#include <string>
using namespace std;

class Ball {
public:
// 宣告靜態資料成員
static double PI;

Ball();
Ball(double, const char*);
Ball(double, string&);

// 宣告靜態函式
static double toRadian(double);

double radius() {
return _radius;
}

string& name() {
return _name;
}

void radius(double radius) {
_radius = radius;
}

void name(const char *name) {
_name = name;
}

void name(string& name) {
_name = name;
}

double volumn() {
return (4 / 3 * PI * _radius * _radius * _radius);
}

private:
double _radius; // 半徑
string _name; // 名稱
};

  • Ball.cpp
#include <string>
#include "Ball.h"
using namespace std;

// 初始靜態資料成員
double Ball::PI = 3.14159;

// 實作靜態函式
double Ball::toRadian(double angle) {
return 3.14159 / 180 * angle;
}

// 預設建構函式
Ball::Ball() {
_radius = 0.0;
_name = "noname ball";
}

Ball::Ball(double radius, const char *name) {
_radius = radius;
_name = name;
}

Ball::Ball(double radius, string &name) {
_radius = radius;
_name = name;
}

與靜態資料成員一樣的,您可以透過類別名稱使用::運算子來存取"static"函式,當然要注意權限設定,例如設定為"public"的話可以如下存 取:
cout << "角度90等於徑度"
         << Ball::toRadian(90)
         << endl;

由於靜態成員是屬於類別而不是物件,所以當您呼叫靜態函式時,並不會傳入物件的位址,所以靜態函式中不會有this指標,由於沒有this指標,所以在C ++的靜態函式中不允許使用非靜態成員,因為沒有this來儲存物件的位址,也就無法辨別要存取的是哪一個物件的成員,事實上,如果您在靜態函式中使用非 靜態資料成員,在編譯時就會出現以下的錯誤訊息:
invalid use of member `Ball::_radius' in static member function

或者是在靜態函式中呼叫非靜態函式,在編譯時就會出現以下的錯誤訊息:
cannot call member function `std::string& Ball::name()' without object