Menu
Coddy logo textTech

アクセス修飾子の詳細

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 35/104。

3つのアクセス修飾子について理解したところで、同じクラスのオブジェクトが複数ある場合に、それらがどのように動作するかを見ていきましょう。よくある誤解は、privateが「このオブジェクトのみ」を意味するというものですが、実際には「このクラスのみ」を意味します。

同じクラスのオブジェクトは、お互いの非公開(private)メンバにアクセスできます:

class Person {
    std::string secret;
    
public:
    Person(std::string s) : secret(s) {}
    
    void readSecret(const Person& other) {
        // 他のオブジェクトの非公開メンバへのアクセス - 許可されています!
        std::cout << other.secret;
    }
};

これは、アクセス制御がオブジェクトレベルではなく、クラスレベルで強制されるためです。readSecret メソッドは Person クラスの一部であるため、任意の Person オブジェクトのプライベートメンバにアクセスできます。この設計により、コピーコンストラクタや比較演算子などの操作が、他のオブジェクトの内部状態を扱えるようになります。

クラス内でアクセス修飾子を複数回切り替えることもできます:

class Mixed {
public:
    void publicMethod1();
    
private:
    int privateData;
    
public:
    void publicMethod2();    // 再びpublicへ
    
private:
    void privateHelper();    // 再びprivateへ
};

これは有効なC++ですが、可読性のために、一般的にはアクセスレベルごとにメンバーをグループ化するのがより良い方法です。ほとんどのスタイルガイドでは、publicメンバーを最初に記述し(これらがクラスのインターフェースを形成するため)、その後にprotected、次にprivateと続けることを推奨しています。

challenge icon

チャレンジ

簡単

同じクラスのオブジェクトが互いのプライベートメンバにどのようにアクセスできるかを示す、ウォレット比較システムを構築しましょう。これはC++のアクセス制御に関する重要な洞察です。アクセス制御はオブジェクトレベルではなく、クラスレベルで強制されます。

コードを整理するために、2つのファイルを作成します:

  • Wallet.h: プライベートな財務データを保存しつつ、ウォレット間の比較を可能にする Wallet クラスを定義します。クラスには以下を含める必要があります:
    • プライベートメンバ: ownerName (string) と balance (double)
    • 所有者名と初期残高を受け取るコンストラクタ
    • 所有者の名前を返すパブリックなゲッター getOwnerName()
    • このウォレットの残高を別のウォレットのプライベートな残高と比較し、このウォレットの方がお金が多い場合に true を返すメソッド hasMoreThan(const Wallet& other)
    • 両方のウォレットのプライベートな残高の合計を返すメソッド combinedBalance(const Wallet& other)
    • このウォレットから別のウォレットにお金を移動させるメソッド transferTo(Wallet& other, double amount)。これは両方のウォレットのプライベートな残高を直接変更する必要があります(金額が正であり、このウォレットの残高を超えない場合に限ります)。
  • main.cpp: オブジェクト間のプライベートメンバへのアクセスを実演します。入力から2つの所有者名と2つの残高を読み取り(name1, balance1, name2, balance2 の4行)、以下の処理を行います:
    • 入力値を使用して2つの Wallet オブジェクトを作成します
    • combinedBalance() を使用して "Combined wealth: "Combined wealth: $"lt;amount>" と出力します
    • ウォレットを比較し、残高が多い方の所有者について "<name> has more money" と出力します(判定には hasMoreThan() を使用してください)
    • transferTo() を使用して、最初のウォレットから2番目のウォレットへ 100.0 を送金します
    • "After transfer:" と出力します
    • 再び "Combined wealth: "Combined wealth: $"lt;amount>" と出力します(値は変わっていないはずです)
    • 再度比較し、"<name> has more money" と出力します(結果が変わっている可能性があります)

ここでの重要な概念は、hasMoreThan()transferTo() といったメソッドが、別の Wallet オブジェクトのプライベートな balance メンバに直接アクセスできるということです。ゲッターは必要ありません。これは、C++のアクセス制御がクラスベースであるためです。Wallet クラス内のコードであれば、どの Wallet オブジェクトのプライベートメンバにもアクセスできます。

すべての通貨価値は、<iomanip>std::fixedstd::setprecision(2) を使用して小数点以下2桁でフォーマットしてください。残高の入力は std::stod() を使用して変換してください。

チートシート

C++におけるアクセス制御は、オブジェクトレベルではなくクラスレベルで適用されます。これは、同じクラスのオブジェクト同士であれば、お互いの非公開(private)メンバにアクセスできることを意味します:

class Person {
    std::string secret;
    
public:
    Person(std::string s) : secret(s) {}
    
    void readSecret(const Person& other) {
        // 他のオブジェクトのprivateメンバへのアクセス - 許可されています!
        std::cout << other.secret;
    }
};

readSecretメソッドは、Personクラスの一部であるため、任意のPersonオブジェクトの非公開メンバであるsecretにアクセスできます。この設計により、コピーコンストラクタや比較演算子などの操作が可能になります。

クラス内では、アクセス修飾子を何度でも切り替えることができます:

class Mixed {
public:
    void publicMethod1();
    
private:
    int privateData;
    
public:
    void publicMethod2();    // 再びpublicへ
    
private:
    void privateHelper();    // 再びprivateへ
};

ただし、可読性の観点からは、メンバをアクセスレベルごとにグループ化するのがより良い習慣です。ほとんどのスタイルガイドでは、最初にpublicメンバを記述し、次にprotected、最後にprivateを記述することを推奨しています。

自分で試してみよう

#include <iostream>
#include <string>
#include <iomanip>
#include "Wallet.h"

using namespace std;

int main() {
    // 入力を読み込む: name1, balance1, name2, balance2
    string name1, name2;
    string balanceStr1, balanceStr2;
    
    getline(cin, name1);
    getline(cin, balanceStr1);
    getline(cin, name2);
    getline(cin, balanceStr2);
    
    double balance1 = stod(balanceStr1);
    double balance2 = stod(balanceStr2);
    
    // 通貨価値のための出力フォーマットを設定する
    cout << fixed << setprecision(2);
    
    // TODO: 入力値を使用して2つの Wallet オブジェクトを作成する
    
    // TODO: combinedBalance() を使用して合計資産を出力する
    // フォーマット: "Combined wealth: $<amount>"
    
    // TODO: hasMoreThan() を使用してウォレットを比較し、どちらがより多くのお金を持っているか出力する
    // フォーマット: "<name> has more money"
    
    // TODO: transferTo() を使用して、最初のウォレットから2番目のウォレットへ 100.0 を送金する
    
    // TODO: "After transfer:" を出力する
    
    // TODO: 合計資産を再度出力する
    
    // TODO: 再度比較し、どちらがより多くのお金を持っているか出力する
    
    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン