靜態成員函數 Static Member Function

前一章我們介紹了什麼是 靜態成員變數,這章我們要來介紹另一個成員,也就是靜態成員函數 Static Member Function!

什麼是靜態成員函數

在前一章我們已經知道了什麼是靜態成員變數,但那個並不是類別中唯一的靜態成員。

函數也可以是靜態成員,就叫做靜態成員函數。

我們直接來看一個例子:

class Object
{
public:
    static int value;

    static int getValue()
    {
        return value;
    }
};

int Object::value = 1;

int main() {
    std::cout << Object::getValue() << std::endl;

    return 0;
}

建立一個靜態成員函數很簡單,我們在一般的函數前面加上關鍵字 static 就可以啦!

它的概念和靜態成員變數相同,一樣是屬於類別,不屬於實體物件,因此可以在沒有物件被生成前就呼叫!

我們一樣透過範圍解析運算子 :: 來呼叫靜態成員函數。

定義靜態成員函數

和一般的函數相同,我們也可以在類別之外定義靜態成員函數。

像是這樣:

class Object
{
public:
    // 告訴編譯器說我們有這兩個東西
    static int value;
    static int getValue();
};

// 告訴編譯器那兩個東西實際上是什麼
int Object::value = 1;
int Object::getValue()
{
    return value;
}

int main() {
    std::cout << Object::getValue() << std::endl;

    return 0;
}

限制

靜態成員函數有兩個非常重要的限制!

  1. 沒有 this 指標
  2. 只能使用靜態成員變數

我們還沒有講什麼是 this 指標,所以這裡先跳過,我們直接來講講第二點。

如果靜態成員函數嘗試使用一般的變數,那麼程式就會報錯。

比如說:

class Object
{
public:
    // value 為一般變數
    int value = 0;

    static int getValue()
    {
        return value;
    }
};

int main() {
    std::cout << Object::getValue() << std::endl;

    return 0;
}

這邊我們將 value 由靜態變數轉為一般變數,我們可以看到程式報出類似這樣的錯誤:

error: invalid use of member 'Object::value' in static member function

為什麼這樣設計呢?

我們知道靜態成員函數可以在實體物件被創立前被呼叫,但一般的變數是在實體物件被創立後才出現的。如果靜態成員函數可以在一般的變數創立前就使用它的話,不是很奇怪嗎?

實際範例

那麼我們什麼時候應該在類別中使用靜態成員函數而非一般的函數呢?

當一個函數與整個類別有直接/間接關聯,而不只是和某個特定的實體物件關聯時,我們應該使用靜態函數。

以下是一些例子:

實用函數

靜態成員函數通常用於不需要使用特定實體物件的實用函數。

比如說,一個 StringUtil 類別可能有一個靜態成員函數來將字串轉換為大寫:

class StringUtil
{
public:
    static std::string toUpperCase(const std::string& str) {
        std::string result = str;
        for (char& c : result) {
            c = std::toupper(c);
        }
        return result;
    }
};

int main() {
    std::string text = "hello world";
    std::string upperText = StringUtil::toUpperCase(text);
    std::cout << "大寫 text: " << upperText << std::endl;
    return 0;
}
管理共享資源

靜態成員函數對於管理類別中的共享資源非常有用。

比如說,一個 DatabaseConnection 類可能有一個靜態成員函數來建立和資料庫的連接:

class DatabaseConnection
{
public:
    static void connect() {
        // 建立數據庫連接的程式碼
        // ...
        std::cout << "已連接到數據庫" << std::endl;
    }
};

int main() {
    DatabaseConnection::connect();
    return 0;
}
設計模式

在程式設計模式中,靜態成員函數可以作為工廠方法(Factory Method)來創立類別的的實體物件。

例如,一個 Shape 類可能有一個靜態成員函數來創建不同類型的形狀:

class Shape
{
public:
    static Shape createRectangle(int width, int height) {
        Shape rectangle;
        rectangle.width = width;
        rectangle.height = height;
        return rectangle;
    }

    void display() {
        std::cout << "矩形寬度:" << width << ",高度:" << height << std::endl;
    }

private:
    int width;
    int height;
};

int main() {
    Shape rectangle = Shape::createRectangle(10, 5);
    rectangle.display();
    return 0;
}

總結

這章我們了解了什麼是靜態成員函數 Static Member Function,它的作用以及實際例子。

下一章我們會來介紹什麼是朋友類別 Friend Class。那就希望這章有讓你們學到新東西啦!