結論: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つは、struct を class に書き換えただけです。
struct Point { int x; int y; }; // 既定は public(外から見える)
class Point { int x; int y; }; // 既定は private(外から隠れる)
struct… メンバは既定で public(外からp.xで触れる)class… メンバは既定で private(外からp.xで触れない)
つまり文法上の違いはこれだけです。「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 → アクセス指定子 → メンバ関数 → コンストラクタ)が「クラスの基礎」です。この先に、複数のクラスで共通部分をまとめる 継承 が続き、オブジェクト指向らしい設計に入っていきます。
つまずきやすいところ
- class で書いたら外から触れなくなった:class は既定 private です。外から使いたいメンバは
public:の下に書きます。struct なら既定 public なので、この違いを忘れると「なぜか見えない」で詰まります。 - const メンバ関数の中で値を書き換えてしまう:
int get() constのように const を付けた関数の中でメンバを変更すると、コンパイラがpassing 'const ...' as 'this' argument discards qualifiersというエラーを出します。意味と直し方は C++のエラー逆引き(const違反) を参照してください。 - メンバ名のタイプミス:
has no member named ...はスペル違いのサインです。逆引きは C++のエラー一覧 にまとまっています。
次に読む
- structとclass ― データをまとめる(ブラウザ実行)― この記事の中心。まず動かす
- メンバ関数 ― データに振る舞いを持たせる(ブラウザ実行)
- コンストラクタ ― 生成時に初期化する(ブラウザ実行)
- this と const メンバ関数(ブラウザ実行)
- 継承 ― 共通部分をまとめる(ブラウザ実行)
- C++の独学ロードマップ ― クラスを含めた学習の全体像
- C言語とC++の違い ― どちらから学ぶか迷っている人向け