【C++】クラスメンバ徹底解説(変数・関数・型・アクセス制御)

目次

はじめに

C++のクラスは、オブジェクトの「設計図」です。この設計図は、メンバと呼ばれる様々な要素から構成されます。メンバを大きく分類すると、データを保持するための「メンバ変数」、操作を定義する「メンバ関数」、そしてクラス固有のを定義する「メンバ型」の3つに分けられます。

これらのメンバを適切に設計し、後述するアクセス制御を組み合わせることで、安全で再利用性の高い、カプセル化されたクラスを構築できます。この記事では、これらのクラスメンバの全貌を網羅的に解説します。


1. メンバ変数 (Member Variables)

オブジェクトの状態(データ)を保持します。

非静的メンバ変数

最も一般的なメンバ変数で、オブジェクトごとに個別の値を持ちます。

class Player {
public:
    // C++11以降、非静的メンバ変数は宣言時に直接初期化できる
    std::string name = "名無し";
    int level = 1;
};

静的メンバ変数 (static)

staticで宣言された変数は、特定のオブジェクトに属さず、そのクラス全体で共有されます。

class GameSession {
public:
    static int active_players; // 宣言
    GameSession() { active_players++; }
    ~GameSession() { active_players--; }
};
// クラスの外で定義と初期化が必要
int GameSession::active_players = 0;

mutable 指定子

constメンバ関数(オブジェクトを変更しないと約束した関数)内で、例外的に変更を許可したいメンバ変数に mutable を付けます。

class DataCache {
private:
    mutable int access_count = 0;
public:
    std::string getData() const {
        access_count++; // const関数内でもmutableなメンバは変更可能
        return "some_data";
    }
};

2. メンバ関数 (Member Functions)

オブジェクトの振る舞い(操作)を定義します。

コンストラクタ

オブジェクトが生成される際に自動で呼ばれる初期化用の関数。

class Widget {
private:
    int id_;
    std::string name_;
public:
    // デフォルトコンストラクタ
    Widget() : id_(-1), name_("default") {}

    // 引数付きコンストラクタ
    explicit Widget(int id) : id_(id), name_("custom") {}

    // 委譲コンストラクタ
    Widget(int id, std::string name) : id_(id), name_(name) {}
    Widget(std::string name) : Widget(0, name) {} // 他のコンストラクタに処理を委譲
};
  • explicit: Widget w = 1; のような暗黙の型変換を禁止します。

デストラクタ

オブジェクトが破棄される際に自動で呼ばれる後片付け用の関数。~クラス名() という名前です。

コピー/ムーブ操作

  • コピーコンストラクタ: Widget w2 = w1;
  • コピー代入演算子: w2 = w1;
  • ムーブコンストラクタ: Widget w3 = std::move(w1);
  • ムーブ代入演算子: w3 = std::move(w2);

= default / = delete

コンパイラが自動生成できる特殊なメンバ関数について、

  • = default: コンパイラに自動生成を明示的に依頼する。
  • = delete: そのメンバ関数の生成を禁止する(コピー禁止など)。
struct NonCopyable {
    NonCopyable(const NonCopyable&) = delete;
    NonCopyable& operator=(const NonCopyable&) = delete;
};

静的メンバ関数 (static)

static で宣言されたメンバ関数は、クラス全体に関連付けられ、クラス名::関数名() のようにオブジェクトなしで呼び出せます。

型変換演算子

operator 型名() という形式で定義し、自作クラスを他の型に変換できるようにします。

struct Switch {
    bool is_on = false;
    // Switchをboolに変換できるようにする
    explicit operator bool() const { return is_on; }
};
Switch s;
if (s) { /* ... */ } // explicitなので if(s) のような文脈でのみ有効

3. メンバ型 (Member Types)

クラスのスコープ内で、新しい型を定義したり、既存の型に別名を付けたりします。

クラス内クラス(ネストしたクラス)

class Outer {
public:
    struct Inner { int value; };
private:
    Inner inner_data;
};
// Outer::Inner inner_obj; のように外部からもアクセス可能

型の別名宣言 (using)

template<typename T>
class MyContainer {
public:
    // T型に value_type という別名を付ける (typedef int value_type; とほぼ同じ)
    using value_type = T;
};

4. アクセス制御

メンバへのアクセス権限を制御します。

指定子説明
public公開: どこからでもアクセス可能。クラスのインターフェース。
protected限定公開: そのクラスと、その子クラスの内部からのみアクセス可能。
private非公開: そのクラスの内部からのみアクセス可能。実装の詳細を隠蔽する。
friend友達: friend宣言された外部の関数やクラスに、privateメンバへのアクセスを特別に許可する。

まとめ

クラスは、これらの「メンバ変数」「メンバ関数」「メンバ型」という部品と、「アクセス制御」の仕組みを組み合わせることで、一つの完成した「モノ」として設計されます。それぞれのメンバの役割を理解し、適切に組み合わせることが、オブジェクト指向プログラミングの鍵となります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次