發新話題

C++ Gossip - 物件基礎《封裝》static 成員

C++ Gossip - 物件基礎《封裝》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:I = 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:I
         << 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:I = 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

TOP

發新話題

本站所有圖文均屬網友發表,僅代表作者的觀點與本站無關,如有侵權請通知版主會盡快刪除。