本文へスキップ
BecomeCoder
ブログ一覧Wikiコース一覧

C++のクラスの使い方入門|struct(構造体)との違いから学ぶ

#C++#クラス#struct#初心者#オブジェクト指向

結論:C++のクラス(class)と構造体(struct)は「ほぼ同じもの」で、違うのは”既定の公開範囲”だけです。struct は既定 public(外から見える)、class は既定 private(外から隠す)。この「隠す」しくみ=カプセル化がクラスの核心で、そこにメンバ関数・アクセス指定子・コンストラクタを足していくのがオブジェクト指向の入口です。

「classとstructって何が違うの?」でつまずく人はとても多いです。この記事は、その一点に絞って、書き方を順番に手を動かしながら理解できるようにします。C++の学習順序そのものは C++の独学ロードマップ を、C言語との違いは C言語とC++の違い を参照してください。ここでは「クラスの書き方」だけを深掘りします。

まず struct(構造体)=「データの束」から

クラスを理解する近道は、先に struct を知ることです。struct は、関連する複数の値を1つにまとめた「自分だけの型」です。

struct Point {
    int x;
    int y;
};

Point p;
p.x = 3;
p.y = 4;   // .(ドット)でアクセス

Point という新しい型を作り、p という変数(インスタンス)を1つ作りました。中の値には .(ドット)で触ります。ここまでは「x と y をセットで持ち運べる箱」にすぎません。

このコードは Become-Coder の structとclass ― データをまとめる の回で、ブラウザにそのまま貼って実行できます(環境構築なし・無料・登録不要)。C++コースは後半が本物のコンパイラで動くので、{10, 20} のようなまとめて初期化も、その場で結果を確かめられます。

class は struct と「ほぼ同じ」。違いは既定の公開範囲だけ

ここが本題です。次の2つは、structclass に書き換えただけです。

struct Point { int x; int y; };   // 既定は public(外から見える)
class  Point { int x; int y; };   // 既定は private(外から隠れる)

つまり文法上の違いはこれだけです。「classは高機能でstructは簡易版」ではありません。どちらもメンバ関数もコンストラクタも継承も持てます。 違うのは”最初に隠すか・見せるか”のデフォルトだけ。

では、なぜ「隠す」ことに意味があるのでしょうか。

アクセス指定子 public / private ―「隠して守る」

外から自由に書き換えられると、値が壊れても原因が追えません。そこで「外から触れる入口」と「中だけで使う部品」を分けます。これがアクセス指定子です。

class Counter {
private:
    int count = 0;              // 外から直接触らせない
public:
    void increment() { count++; }   // 公開した操作
    int get() { return count; }      // 公開した操作
};

Counter c;
c.increment();
c.increment();
// c.count = 100;   // ← エラー:private なので外から触れない
cout << c.get();     // 2

count を private にしたことで、「増やす」「読む」という決められた入口経由でしか触れなくなりました。これがカプセル化です。慣習として、単純なデータの束は struct、振る舞いを持たせて守る部品は class を使い分けます。

この動く例は structとclass の回にあります。コメント// c.count = 100; を外して実行すると、コンパイラが実際にエラーを出すのを確認できます。「なぜエラーになるか」を目で見ると腹落ちが速いです。

メンバ関数 ―「データに振る舞いを持たせる」

上の increment()get() のように、クラスの中に書いた関数をメンバ関数と呼びます。データ(count)と、それを扱う操作(increment)を同じ型の中にまとめられるのがクラスの利点です。

メンバ関数だけを取り出して手を動かすなら メンバ関数 ― データに振る舞いを持たせる が専用の回です(ブラウザ実行)。さらに「このメンバ関数は中身を変更しない」と宣言する const メンバ関数や this の話は this と const メンバ関数 に進みます。

コンストラクタ ―「生成時に必ず初期化する」

Counter c; のあとに毎回 count を 0 にセットするのは面倒だし、忘れると未初期化のゴミが入ります。そこで「インスタンスを作った瞬間に自動で走る初期化処理」=コンストラクタを使います。

class Counter {
private:
    int count;
public:
    Counter(int start) { count = start; }   // コンストラクタ
    int get() { return count; }
};

Counter c(10);   // 作ると同時に 10 で初期化
cout << c.get(); // 10

クラス名と同じ名前の関数がコンストラクタです。これで「作ったのに初期化し忘れる」バグを構造的に防げます。実際に動かすなら コンストラクタ ― 生成時に初期化する を開いてください(ブラウザ実行)。

ここまで(struct/class → アクセス指定子 → メンバ関数 → コンストラクタ)が「クラスの基礎」です。この先に、複数のクラスで共通部分をまとめる 継承 が続き、オブジェクト指向らしい設計に入っていきます。

つまずきやすいところ

次に読む

← ブログ一覧に戻る