【C++】カプセル化とは?public, private, protected の違いと使い方

目次

はじめに

オブジェクト指向プログラミングの三本柱の一つである「カプセル化 (Encapsulation)」は、**データ(メンバ変数)と、それを操作する手続き(メンバ関数)**を一つにまとめ、重要なデータを外部から守るための仕組みです。

C++では、アクセス指定子public, private, protected)を使うことで、このカプセル化を実現します。これにより、オブジェクトの利用者は、知る必要のない内部構造を意識することなく、公開された安全な窓口(メンバ関数)だけを使ってオブジェクトを操作できます。

この記事では、3種類のアクセス指定子の役割と、カプセル化がなぜ重要なのかを、具体的なサンプルコードと共に解説します。


アクセス指定子の種類と役割

アクセス指定子は、クラスのメンバが、クラスの外部からアクセスできるかどうかを制御します。

  • public:: 公開public: 以降に宣言されたメンバは、クラスの外部から誰でも自由にアクセスできます。
  • private:: 非公開private: 以降に宣言されたメンバは、そのクラスの内部にあるメンバ関数からしかアクセスできません。外部からは完全に隠されます。クラスでアクセス指定子を省略した場合、デフォルトで private になります。
  • protected:: private に似ていますが、継承された子クラスからはアクセスが許可される、という特徴があります。

カプセル化の実践サンプルコード

このコードは、BankAccount(銀行口座)クラスを例に、口座残高(balance)を private にして外部から直接変更できないように保護し、public なメンバ関数(deposit, withdraw, getBalance)を通じてのみ、安全に操作できるようにしています。

完成コード

#include <iostream>
#include <string>

using namespace std;

class BankAccount {
private:
    // メンバ変数をprivateで宣言し、外部から隠蔽する
    string ownerName; // 口座名義人
    long balance;     // 残高

public:
    // コンストラクタ(オブジェクト作成時の初期化処理)
    BankAccount(string name, long initialDeposit) {
        ownerName = name;
        balance = initialDeposit;
    }

    // publicなメンバ関数を、操作のための窓口として公開する
    void deposit(long amount) { // 入金
        if (amount > 0) {
            balance += amount;
            cout << amount << "円を入金しました。残高: " << balance << "円" << endl;
        }
    }

    void withdraw(long amount) { // 出金
        if (amount > 0 && balance >= amount) {
            balance -= amount;
            cout << amount << "円を出金しました。残高: " << balance << "円" << endl;
        } else {
            cout << "出金できませんでした。" << endl;
        }
    }

    long getBalance() { // 残高照会
        return balance;
    }
};

int main() {
    // BankAccountオブジェクトを作成
    BankAccount myAccount("山田 太郎", 50000);

    // publicなメンバ関数経由で操作
    myAccount.deposit(10000);
    myAccount.withdraw(5000);

    // privateなメンバ変数に直接アクセスしようとすると、コンパイルエラーになる
    // myAccount.balance = 999999; // エラー! balanceはprivateです

    cout << "最終残高: " << myAccount.getBalance() << "円" << endl;

    return 0;
}

コードの解説とカプセル化の目的

データの隠蔽

balance(残高)という非常に重要なデータは private で宣言されています。これにより、main関数の中から myAccount.balance = 999999; のように、値を直接、不正に書き換えることができなくなります。

公開された操作の窓口

balance を変更する唯一の方法は、public で公開された deposit(入金)や withdraw(出金)といったメンバ関数を呼び出すことです。

カプセル化の目的

なぜこのようなことをするのでしょうか?それは、オブジェクトの安全性を保つためです。 withdraw 関数の中には、balance >= amount というチェックがあり、残高以上の金額は引き出せないようになっています。もし balancepublic で、誰でも直接変更できてしまったら、この重要なチェックを無視して、残高をマイナスにすることも可能になってしまいます。

このように、カプセル化は、クラスの作者が意図した、安全で正しい方法でしかデータが操作されないことを保証するための、非常に重要な仕組みなのです。これにより、クラスの利用者は、その内部の詳細を気にすることなく、安心してそのクラス(オブジェクト)を使うことができます。


まとめ

今回は、オブジェクト指向の重要な柱である「カプセル化」と、それを実現するためのアクセス指定子について解説しました。

  • カプセル化とは、データと操作をまとめ、データを外部から保護(隠蔽)する仕組み。
  • private: メンバを隠す。クラス内部からのみアクセス可。
  • public: メンバを公開する。外部からの操作の窓口となる。
  • protected: private に近いが、子クラスからのアクセスを許可する(継承で利用)。

メンバ変数は原則として private にし、それらを操作するための public なメンバ関数を提供する、という設計が、カプセル化の基本であり、高品質で再利用しやすいクラスを作成するための第一歩です。

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

この記事を書いた人

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

目次