【C++】staticとは?|使い方と用途をわかりやすく解説

サムネイル画像 C++

今回は、C++での「static」について解説していきます。

「staticって何?」「どんな時に使うの?」と疑問に思ったことはありませんか?

この記事を読み終えると、あなたはstaticの使い方をマスターできると思いますので、ぜひ最後まで読んでいただけると嬉しいです。

staticとは?

staticとは、

・「この変数や関数は特別な扱いをしますよ」
記憶域期間やスコープを制御するためのキーワード

です。

C++では、staticは使う場所によって意味が変わります

  • 関数内のstatic変数:プログラム終了まで値を保持
  • クラスのstaticメンバ:すべてのインスタンスで共有される
  • グローバルなstatic変数・関数:そのファイル内でのみ使用可能

それぞれ詳しく見ていきましょう。

関数内のstatic変数

関数内でstatic変数を宣言すると、その変数は関数が終了しても値を保持し続けます

▼main.cpp

#include <iostream>

void countCall() {
    static int count = 0; // 初回のみ実行される
    count++;
    std::cout << "Called " << count << " times\n";
}

int main() {
    countCall();
    countCall();
    countCall();
    
    return 0;
}

実行結果

Called 1 times
Called 2 times
Called 3 times

通常の変数なら毎回0に初期化されますが、static変数は値を保持し続けます

staticを付けない場合と比較してみましょう。

▼main.cpp

#include <iostream>

void countCallNormal() {
    int count = 0; // staticなし
    count++;
    std::cout << "Called " << count << " times\n";
}

int main() {
    countCallNormal();
    countCallNormal();
    countCallNormal();
    
    return 0;
}

実行結果

Called 1 times
Called 1 times
Called 1 times

staticなしでは、毎回0にリセットされてしまいます

クラスのstaticメンバ変数

クラスでstatic変数を宣言すると、すべてのインスタンスで共有される変数になります。

▼main.cpp

#include <iostream>

class Player {
public:
    static int totalPlayers; // static メンバ変数
    
    Player() {
        totalPlayers++;
    }
};

// static メンバ変数の定義(クラス外で必要)
int Player::totalPlayers = 0;

int main() {
    std::cout << "Total: " << Player::totalPlayers << "\n";
    
    Player p1;
    std::cout << "Total: " << Player::totalPlayers << "\n";
    
    Player p2;
    std::cout << "Total: " << Player::totalPlayers << "\n";
    
    return 0;
}

実行結果

Total: 0
Total: 1
Total: 2

staticメンバ変数は、各インスタンスごとではなく、クラス全体で1つだけ存在します

重要なポイント

  • staticメンバ変数はクラス外で定義が必要
  • クラス名::変数名でアクセスできる
  • すべてのインスタンスで値を共有する

クラスのstaticメンバ関数

staticメンバ関数は、インスタンスを作らずに呼び出せる関数です。

▼main.cpp

#include <iostream>

class Math {
public:
    static int add(int a, int b) {
        return a + b;
    }
    
    static int multiply(int a, int b) {
        return a * b;
    }
};

int main() {
    // インスタンスを作らずに呼び出せる
    std::cout << "3 + 5 = " << Math::add(3, 5) << "\n";
    std::cout << "3 * 5 = " << Math::multiply(3, 5) << "\n";
    
    return 0;
}

実行結果

3 + 5 = 8
3 * 5 = 15

staticメンバ関数は、非staticメンバ変数にアクセスできないという制限があります。

▼main.cpp

#include <iostream>

class Example {
public:
    int normalVar = 10;
    static int staticVar;
    
    static void showStatic() {
        std::cout << staticVar << "\n";      // OK
        // std::cout << normalVar << "\n";   // エラー!
    }
};

int Example::staticVar = 20;

int main() {
    Example::showStatic();
    return 0;
}

実行結果

20

staticメンバ関数はインスタンスに紐づかないため、通常のメンバ変数にはアクセスできません

グローバルなstatic変数・関数

ファイルのグローバルスコープでstaticを使うと、その変数や関数はそのファイル内でのみ使用可能になります。

▼sub.cpp

static int secret = 100; // このファイル内でのみ使える

static void privateFunc() {
    // このファイル内でのみ呼び出せる
}

▼main.cpp

#include <iostream>

// extern int secret; // エラー!他のファイルのstatic変数は使えない

int main() {
    // privateFunc(); // エラー!他のファイルのstatic関数は呼べない
    return 0;
}

これにより、ファイル内部の実装を隠蔽できます

モダンC++では、staticの代わりに無名名前空間(namespace)を使う方が推奨されています。

▼sub.cpp

namespace {
    int secret = 100; // このファイル内でのみ使える
    
    void privateFunc() {
        // このファイル内でのみ呼び出せる
    }
}

実践的な使い方

staticのよくある使い方を見てみましょう。

シングルトンパターン

staticメンバを使って、クラスのインスタンスを1つだけに制限できます。

▼main.cpp

#include <iostream>

class Singleton {
private:
    static Singleton* instance;
    Singleton() {} // コンストラクタをprivateに
    
public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
    
    void showMessage() {
        std::cout << "Singleton instance\n";
    }
};

Singleton* Singleton::instance = nullptr;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    
    s1->showMessage();
    
    // s1とs2は同じインスタンス
    std::cout << (s1 == s2 ? "Same instance" : "Different instance");
    
    return 0;
}

実行結果

Singleton instance
Same instance

staticを使うべき場面

staticは以下のような場面で使います。

  • 関数内static変数:関数の呼び出し回数をカウントしたい時
  • クラスのstaticメンバ変数:すべてのインスタンスで共有したいデータがある時
  • クラスのstaticメンバ関数:インスタンスなしで呼び出したいユーティリティ関数
  • グローバルstatic:ファイル内部の実装を隠蔽したい時(モダンC++では無名名前空間推奨)

まとめ

staticの使い方をまとめます。

  • 関数内static変数:値を保持し続ける
  • クラスのstaticメンバ変数:すべてのインスタンスで共有される
  • クラスのstaticメンバ関数:インスタンスなしで呼び出せる
  • グローバルstatic:そのファイル内でのみ使用可能(モダンC++では無名名前空間推奨)
  • staticメンバ変数はクラス外で定義が必要

これでstaticの使い方はバッチリですね!

適切な場面でstaticを活用して、より効率的なC++プログラムを書いてみてください。

ここまで読んでくださり、ありがとうございました。

この記事が皆様の学習に役立てば幸いです。