[C++] クラスで新しいメンバ変数を宣言する方法と修飾子の注意点

C++でクラスに新しいメンバ変数を宣言するには、クラス定義内で変数を指定します。

例えば、int age;のように型と変数名を記述します。

メンバ変数にはアクセス修飾子publicprotectedprivateを指定して、外部からのアクセス制御を行います。

publicは外部から直接アクセス可能、protectedは派生クラスからアクセス可能、privateはクラス内部のみでアクセス可能です。

デフォルトでは、クラスのメンバ変数はprivateです。

この記事でわかること
  • メンバ変数の宣言と初期化方法
  • アクセス修飾子の役割と使い方
  • 静的メンバ変数の管理方法
  • constメンバ変数の初期化の重要性
  • カプセル化によるデータ保護の意義

目次から探す

クラスにおけるメンバ変数の基本

メンバ変数とは何か

メンバ変数は、クラスのインスタンス(オブジェクト)が持つデータを表します。

これにより、オブジェクトの状態を保持し、操作することが可能になります。

メンバ変数は、クラスの内部で定義され、オブジェクトごとに異なる値を持つことができます。

クラス内でのメンバ変数の宣言方法

メンバ変数は、クラスの定義内で宣言します。

以下のサンプルコードでは、MyClassというクラスにmyVariableというメンバ変数を宣言しています。

#include <iostream>
class MyClass {
public:
    int myVariable; // メンバ変数の宣言
};
int main() {
    MyClass obj; // MyClassのインスタンスを生成
    obj.myVariable = 10; // メンバ変数に値を代入
    std::cout << "myVariable: " << obj.myVariable << std::endl; // 出力
    return 0;
}
myVariable: 10

メンバ変数の初期化

メンバ変数は、コンストラクタを使用して初期化することが一般的です。

以下のサンプルコードでは、コンストラクタ内でmyVariableを初期化しています。

#include <iostream>
class MyClass {
public:
    int myVariable; // メンバ変数の宣言
    // コンストラクタ
    MyClass(int value) {
        myVariable = value; // メンバ変数の初期化
    }
};
int main() {
    MyClass obj(20); // MyClassのインスタンスを生成し、初期化
    std::cout << "myVariable: " << obj.myVariable << std::endl; // 出力
    return 0;
}
myVariable: 20

メンバ変数のスコープとライフタイム

メンバ変数のスコープは、クラスのインスタンスが存在する間です。

オブジェクトが生成されると、メンバ変数もメモリに確保され、オブジェクトが破棄されるとメンバ変数も解放されます。

以下のサンプルコードでは、スコープの例を示しています。

#include <iostream>
class MyClass {
public:
    int myVariable; // メンバ変数の宣言
    MyClass(int value) {
        myVariable = value; // メンバ変数の初期化
    }
    void display() {
        std::cout << "myVariable: " << myVariable << std::endl; // 出力
    }
};
int main() {
    MyClass obj(30); // MyClassのインスタンスを生成
    obj.display(); // メンバ関数を呼び出し
    return 0;
}
myVariable: 30

このように、メンバ変数はクラスのインスタンスに関連付けられ、オブジェクトのライフタイムに依存します。

アクセス修飾子の役割

アクセス修飾子は、クラスのメンバ(メンバ変数やメンバ関数)へのアクセス権を制御するためのキーワードです。

これにより、データの隠蔽やカプセル化が実現され、クラスの内部実装を外部から隠すことができます。

アクセス修飾子の種類

C++には主に3つのアクセス修飾子があります。

public

public修飾子が付けられたメンバは、クラスの外部から自由にアクセスできます。

これにより、他のクラスや関数から直接利用できるようになります。

#include <iostream>
class MyClass {
public:
    int myVariable; // publicメンバ変数
    void display() {
        std::cout << "myVariable: " << myVariable << std::endl; // 出力
    }
};
int main() {
    MyClass obj;
    obj.myVariable = 40; // publicメンバにアクセス
    obj.display(); // メンバ関数を呼び出し
    return 0;
}
myVariable: 40

private

private修飾子が付けられたメンバは、クラスの外部からはアクセスできません。

これにより、データの隠蔽が実現され、クラスの内部実装を保護します。

#include <iostream>
class MyClass {
private:
    int myVariable; // privateメンバ変数
public:
    void setVariable(int value) {
        myVariable = value; // privateメンバにアクセス
    }
    void display() {
        std::cout << "myVariable: " << myVariable << std::endl; // 出力
    }
};
int main() {
    MyClass obj;
    obj.setVariable(50); // publicメンバ関数を通じて値を設定
    obj.display(); // メンバ関数を呼び出し
    return 0;
}
myVariable: 50

protected

protected修飾子が付けられたメンバは、同じクラス内およびそのクラスを継承した派生クラスからアクセスできますが、クラスの外部からはアクセスできません。

これにより、継承関係におけるデータの共有が可能になります。

#include <iostream>
class BaseClass {
protected:
    int myVariable; // protectedメンバ変数
public:
    void setVariable(int value) {
        myVariable = value; // protectedメンバにアクセス
    }
};
class DerivedClass : public BaseClass {
public:
    void display() {
        std::cout << "myVariable: " << myVariable << std::endl; // 出力
    }
};
int main() {
    DerivedClass obj;
    obj.setVariable(60); // BaseClassのpublicメンバ関数を通じて値を設定
    obj.display(); // メンバ関数を呼び出し
    return 0;
}
myVariable: 60

デフォルトのアクセス修飾子

クラス内でアクセス修飾子を指定しない場合、デフォルトのアクセス修飾子はprivateです。

つまり、メンバ変数やメンバ関数を何も指定せずに宣言すると、自動的にprivateとして扱われます。

#include <iostream>
class MyClass {
    int myVariable; // デフォルトはprivate
public:
    void setVariable(int value) {
        myVariable = value; // privateメンバにアクセス
    }
    void display() {
        std::cout << "myVariable: " << myVariable << std::endl; // 出力
    }
};
int main() {
    MyClass obj;
    obj.setVariable(70); // publicメンバ関数を通じて値を設定
    obj.display(); // メンバ関数を呼び出し
    return 0;
}
myVariable: 70

アクセス修飾子の使い分け

アクセス修飾子は、クラスの設計において重要な役割を果たします。

以下のポイントを考慮して使い分けると良いでしょう。

スクロールできます
修飾子アクセス範囲使用例
publicクラス外部からアクセス可能APIやライブラリのインターフェース
privateクラス内部からのみアクセス可能内部データの隠蔽
protected派生クラスからアクセス可能継承関係でのデータ共有

このように、適切なアクセス修飾子を選択することで、クラスの設計がより明確になり、保守性が向上します。

メンバ変数の宣言における注意点

メンバ変数の初期化とコンストラクタ

メンバ変数は、コンストラクタを使用して初期化することが推奨されます。

コンストラクタは、オブジェクトが生成される際に自動的に呼び出される特別なメンバ関数です。

以下のサンプルコードでは、コンストラクタを使ってメンバ変数を初期化しています。

#include <iostream>
class MyClass {
public:
    int myVariable; // メンバ変数の宣言
    // コンストラクタ
    MyClass(int value) {
        myVariable = value; // メンバ変数の初期化
    }
};
int main() {
    MyClass obj(80); // MyClassのインスタンスを生成し、初期化
    std::cout << "myVariable: " << obj.myVariable << std::endl; // 出力
    return 0;
}
myVariable: 80

静的メンバ変数の宣言と初期化

静的メンバ変数は、クラスのすべてのインスタンスで共有される変数です。

静的メンバ変数は、クラス内で宣言し、クラス外で初期化する必要があります。

以下のサンプルコードでは、静的メンバ変数の宣言と初期化を示しています。

#include <iostream>
class MyClass {
public:
    static int myStaticVariable; // 静的メンバ変数の宣言
    // 静的メンバ変数の初期化
    static void initialize(int value) {
        myStaticVariable = value;
    }
};
// 静的メンバ変数の初期化
int MyClass::myStaticVariable = 0;
int main() {
    MyClass::initialize(100); // 静的メンバ変数を初期化
    std::cout << "myStaticVariable: " << MyClass::myStaticVariable << std::endl; // 出力
    return 0;
}
myStaticVariable: 100

constメンバ変数の扱い

const修飾子が付けられたメンバ変数は、初期化後に変更できない不変の値を持ちます。

constメンバ変数は、コンストラクタで初期化する必要があります。

以下のサンプルコードでは、constメンバ変数の使用例を示しています。

#include <iostream>
class MyClass {
public:
    const int myConstVariable; // constメンバ変数の宣言
    // コンストラクタ
    MyClass(int value) : myConstVariable(value) {} // 初期化リストを使用
};
int main() {
    MyClass obj(120); // MyClassのインスタンスを生成し、初期化
    std::cout << "myConstVariable: " << obj.myConstVariable << std::endl; // 出力
    return 0;
}
myConstVariable: 120

メンバ変数のメモリ管理

メンバ変数は、オブジェクトのライフタイムに応じてメモリが管理されます。

オブジェクトが生成されると、メンバ変数のためのメモリが確保され、オブジェクトが破棄されるとメモリが解放されます。

動的にメモリを確保する場合は、new演算子を使用し、delete演算子で解放する必要があります。

#include <iostream>
class MyClass {
public:
    int* myDynamicVariable; // 動的メモリを使用するメンバ変数
    // コンストラクタ
    MyClass(int value) {
        myDynamicVariable = new int(value); // メモリを動的に確保
    }
    // デストラクタ
    ~MyClass() {
        delete myDynamicVariable; // メモリを解放
    }
};
int main() {
    MyClass obj(140); // MyClassのインスタンスを生成
    std::cout << "myDynamicVariable: " << *obj.myDynamicVariable << std::endl; // 出力
    return 0;
}
myDynamicVariable: 140

グローバル変数との違い

メンバ変数は、クラスのインスタンスに関連付けられた変数であり、オブジェクトごとに異なる値を持つことができます。

一方、グローバル変数は、プログラム全体で共有される変数であり、どの関数からでもアクセス可能です。

以下のサンプルコードでは、メンバ変数とグローバル変数の違いを示しています。

#include <iostream>
int globalVariable = 200; // グローバル変数の宣言
class MyClass {
public:
    int myVariable; // メンバ変数の宣言
    MyClass(int value) {
        myVariable = value; // メンバ変数の初期化
    }
};
int main() {
    MyClass obj(160); // MyClassのインスタンスを生成
    std::cout << "myVariable: " << obj.myVariable << std::endl; // メンバ変数の出力
    std::cout << "globalVariable: " << globalVariable << std::endl; // グローバル変数の出力
    return 0;
}
myVariable: 160
globalVariable: 200

このように、メンバ変数とグローバル変数は異なるスコープとライフタイムを持ち、それぞれの用途に応じて使い分けることが重要です。

修飾子の応用例

カプセル化とデータの隠蔽

カプセル化は、クラスの内部データを隠蔽し、外部からの不正なアクセスを防ぐための手法です。

private修飾子を使用することで、メンバ変数を外部から隠し、公開メンバ関数を通じてのみデータにアクセスできるようにします。

以下のサンプルコードでは、カプセル化の例を示しています。

#include <iostream>
class BankAccount {
private:
    double balance; // 残高を隠蔽
public:
    BankAccount(double initialBalance) {
        balance = initialBalance; // 初期残高の設定
    }
    void deposit(double amount) {
        balance += amount; // 残高の増加
    }
    void withdraw(double amount) {
        if (amount <= balance) {
            balance -= amount; // 残高の減少
        } else {
            std::cout << "残高不足です。" << std::endl; // エラーメッセージ
        }
    }
    void displayBalance() {
        std::cout << "残高: " << balance << std::endl; // 残高の表示
    }
};
int main() {
    BankAccount account(1000.0); // 銀行口座のインスタンスを生成
    account.deposit(500.0); // 入金
    account.withdraw(200.0); // 引き出し
    account.displayBalance(); // 残高の表示
    return 0;
}
残高: 1300

継承とprotectedの活用

protected修飾子を使用することで、基底クラスのメンバに派生クラスからアクセスできるようになります。

これにより、継承関係においてデータを共有しやすくなります。

以下のサンプルコードでは、protectedメンバの活用例を示しています。

#include <iostream>
class BaseClass {
protected:
    int value; // protectedメンバ変数
public:
    BaseClass(int v) : value(v) {} // コンストラクタ
};
class DerivedClass : public BaseClass {
public:
    DerivedClass(int v) : BaseClass(v) {} // 基底クラスのコンストラクタを呼び出し
    void display() {
        std::cout << "value: " << value << std::endl; // protectedメンバにアクセス
    }
};
int main() {
    DerivedClass obj(300); // 派生クラスのインスタンスを生成
    obj.display(); // メンバ関数を呼び出し
    return 0;
}
value: 300

フレンド関数とアクセス制御

フレンド関数を使用することで、特定の関数に対してクラスのprivateメンバやprotectedメンバにアクセスする権限を与えることができます。

以下のサンプルコードでは、フレンド関数の使用例を示しています。

#include <iostream>
class MyClass {
private:
    int secretValue; // privateメンバ変数
public:
    MyClass(int value) : secretValue(value) {} // コンストラクタ
    // フレンド関数の宣言
    friend void revealSecret(MyClass& obj);
};
// フレンド関数の定義
void revealSecret(MyClass& obj) {
    std::cout << "secretValue: " << obj.secretValue << std::endl; // privateメンバにアクセス
}
int main() {
    MyClass obj(400); // MyClassのインスタンスを生成
    revealSecret(obj); // フレンド関数を呼び出し
    return 0;
}
secretValue: 400

静的メンバ変数を使った共有データ管理

静的メンバ変数は、クラスのすべてのインスタンスで共有されるため、共通のデータを管理するのに便利です。

以下のサンプルコードでは、静的メンバ変数を使用してインスタンスの数を管理しています。

#include <iostream>
class MyClass {
private:
    static int instanceCount; // 静的メンバ変数の宣言
public:
    MyClass() {
        instanceCount++; // インスタンス生成時にカウントを増加
    }
    static int getInstanceCount() {
        return instanceCount; // インスタンス数を返す
    }
};
// 静的メンバ変数の初期化
int MyClass::instanceCount = 0;
int main() {
    MyClass obj1; // インスタンスを生成
    MyClass obj2; // インスタンスを生成
    std::cout << "インスタンス数: " << MyClass::getInstanceCount() << std::endl; // 出力
    return 0;
}
インスタンス数: 2

constメンバ変数を使った不変オブジェクトの設計

constメンバ変数を使用することで、オブジェクトの状態を不変に保つことができます。

これにより、オブジェクトのデータが変更されることを防ぎ、より安全な設計が可能になります。

以下のサンプルコードでは、constメンバ変数を使用した不変オブジェクトの例を示しています。

#include <iostream>
class ImmutablePoint {
private:
    const int x; // constメンバ変数
    const int y; // constメンバ変数
public:
    ImmutablePoint(int xValue, int yValue) : x(xValue), y(yValue) {} // コンストラクタ
    void display() const {
        std::cout << "Point(" << x << ", " << y << ")" << std::endl; // 出力
    }
};
int main() {
    ImmutablePoint point(10, 20); // 不変オブジェクトの生成
    point.display(); // メンバ関数を呼び出し
    return 0;
}
Point(10, 20)

このように、修飾子を適切に活用することで、クラスの設計がより効果的になり、データの安全性や可読性が向上します。

よくある質問

メンバ変数はなぜprivateにするべき?

メンバ変数をprivateにすることで、クラスの内部データを外部から直接アクセスできないようにし、データの隠蔽を実現します。

これにより、以下の利点があります。

  • データの整合性を保つ: 外部からの不正な変更を防ぎ、クラスの状態を一貫性のあるものに保つことができます。
  • カプセル化の促進: クラスの内部実装を隠すことで、クラスの使用者が内部の詳細に依存しないようにし、変更があった場合でも影響を最小限に抑えられます。
  • メンバ関数を通じた制御: publicメンバ関数を介してのみデータにアクセスさせることで、データの変更に対する検証や制約を設けることができます。

静的メンバ変数はどのように初期化するの?

静的メンバ変数は、クラス内で宣言し、クラス外で初期化する必要があります。

初期化は、クラスの外部で行うことで、すべてのインスタンスで共有される静的メンバ変数の値を設定します。

以下の例を参考にしてください。

class MyClass {
public:
    static int myStaticVariable; // 静的メンバ変数の宣言
};
// 静的メンバ変数の初期化
int MyClass::myStaticVariable = 0; // クラス外で初期化
int main() {
    MyClass::myStaticVariable = 100; // 初期化後に値を設定
    return 0;
}

constメンバ変数はどこで初期化すればいい?

constメンバ変数は、コンストラクタの初期化リストを使用して初期化する必要があります。

const修飾子が付けられたメンバ変数は、初期化後に変更できないため、必ずコンストラクタで初期化する必要があります。

以下の例を参考にしてください。

class MyClass {
public:
    const int myConstVariable; // constメンバ変数の宣言
    // コンストラクタ
    MyClass(int value) : myConstVariable(value) {} // 初期化リストを使用
};
int main() {
    MyClass obj(50); // MyClassのインスタンスを生成し、初期化
    return 0;
}

このように、constメンバ変数はコンストラクタの初期化リストを使って初期化することが重要です。

まとめ

この記事では、C++におけるクラスのメンバ変数の宣言方法やアクセス修飾子の役割、さらにはメンバ変数の初期化やメモリ管理について詳しく解説しました。

また、修飾子の応用例として、カプセル化や継承、フレンド関数の活用方法についても触れました。

これらの知識を活用することで、より安全で効率的なクラス設計が可能になりますので、ぜひ実際のプログラミングに取り入れてみてください。

  • URLをコピーしました!
目次から探す