C++の構造体とクラスを完全ガイド!独自の型を作る方法
生徒
「先生、C++で複数のデータをまとめて扱いたいときはどうすればいいですか?名前と年齢と身長をバラバラに管理するのは大変で……。」
先生
「そんなときは『構造体』や『クラス』を使えば、自分専用の新しいデータ型を作って、関連する情報をひとまとめにできますよ。」
生徒
「自分専用の型、ですか?難しそうだけど面白そうですね!」
先生
「大丈夫です。基本的な書き方から、それぞれの違いまで丁寧に解説していきますね!」
1. 構造体とクラスとは?
C++のstruct(構造体)やclass(クラス)は、プログラムの中で関連する複数のデータを一つにまとめるための仕組みです。これまで学んだint(整数型)やdouble(小数型)などは、あらかじめ用意された「標準の型」ですが、これらを組み合わせて「学生型」や「モンスター型」といった独自のデータ型を作ることができます。
プログラミング未経験の方に分かりやすく例えると、これらは「専用の整理箱」や「プロフィール帳のテンプレート」のようなものです。一人分の情報をバラバラの付箋に書くのではなく、一つのファイルに綴じることで、データの管理が格段に楽になり、プログラムの読みやすさ(可読性)も向上します。変数とデータ型の応用として、非常に重要な概念です。
2. 構造体(struct)を使ってデータをまとめる
まずは、よりシンプルな「構造体」から見ていきましょう。構造体は主に「複数の値をセットにして運びたい」というときに使われます。例えば、座標(XとY)や、商品の情報などを扱うのに最適です。
定義するときは struct 構造体名 { ... }; と記述し、中身のデータを「メンバ変数」と呼びます。使い方は、定義した後にその構造体名を「型」として使うだけです。メンバにアクセスするときはドット(.)を使います。
#include <iostream>
#include <string>
// 学生の情報をまとめる構造体(設計図)
struct Student {
std::string name; // 名前
int age; // 年齢
double height; // 身長
};
int main() {
// Student型を使って変数を宣言(実体を作る)
Student taro;
taro.name = "太郎";
taro.age = 18;
taro.height = 170.5;
std::cout << taro.name << "さんは" << taro.age << "歳です。" << std::endl;
return 0;
}
3. クラス(class)の基本とオブジェクト
次に「クラス」です。C++の最大の特徴である「オブジェクト指向」の主役です。クラスも構造体と同じようにデータをまとめられますが、最大の違いは「データだけでなく、それを使った処理(関数)も一緒に閉じ込められる」という点です。
クラスを使って作られた変数のことをオブジェクト(またはインスタンス)と呼びます。クラスは「車の設計図」、オブジェクトは「実際に道路を走っている車」だと考えてください。設計図があれば、同じ種類の車を何台でも作ることができますね。
#include <iostream>
class Counter {
public: // どこからでも触れるようにする「魔法の言葉」
int count = 0;
// 数を増やす処理(メンバ関数)
void increment() {
count++;
}
};
int main() {
Counter myCounter; // オブジェクトの作成
myCounter.increment(); // 1増やす
myCounter.increment(); // さらに1増やす
std::cout << "現在の数は: " << myCounter.count << std::endl;
return 0;
}
実行結果は以下のようになります。
現在の数は: 2
4. アクセス修飾子:publicとprivate
クラスを使う上で非常に大切なのが「隠しごと」をする機能です。これをカプセル化と呼びます。誰でも触れるようにするのを public、クラスの中からしか触れないようにするのを private と指定します。
- public(公開): 外部から自由に見たり書き換えたりできる。
- private(非公開): クラスの内部だけで使う。外部から勝手に書き換えられないので安全。
例えば、銀行口座クラスがあったとき、残高を誰でも勝手に書き換えられたら困りますよね?大事なデータは private に隠し、あらかじめ用意した「預金する」という関数(窓口)を通してのみ操作させることで、データの安全を守るのです。これがプログラミングの設計思想における重要なポイントです。
5. 構造体とクラスのたった一つの違い
実はC++において、機能面での構造体とクラスの違いはたった一つしかありません。それは「何も書かなかったときに、デフォルトで公開か非公開か」という点です。
| 種類 | デフォルトのアクセス権 | 主な使い道 |
|---|---|---|
| struct | public(すべて公開) | 単純なデータの詰め合わせ |
| class | private(隠される) | 複雑な処理や、安全性が求められる設計 |
初心者のうちは、「単に数値をひとまとめにしたいなら struct」「関数なども含めて本格的に部品を作りたいなら class」という使い分けで十分です。
6. メンバ関数を使って「振る舞い」を定義する
クラスの真骨頂は、データ(メンバ変数)をどう扱うかを「メンバ関数」として定義できることです。例えば、「RPGの勇者」という型を作ってみましょう。勇者は名前やHPというデータだけでなく、「攻撃する」というアクション(振る舞い)を持っています。
#include <iostream>
#include <string>
class Hero {
public:
std::string name;
int hp;
// 攻撃の振る舞い
void attack() {
std::cout << name << "の攻撃!敵に10ダメージ!" << std::endl;
}
};
int main() {
Hero sato;
sato.name = "サトシ";
sato.hp = 100;
sato.attack(); // メンバ関数の呼び出し
return 0;
}
7. 構造体の配列で大量のデータを管理
自分で作った「型」は、配列として何十個、何百個と並べることもできます。例えば、名簿管理プログラムなどは、構造体の配列を使うと一気に作りやすくなります。これは、パソコンでExcelの表を作っているような感覚に近いかもしれません。
一行が構造体のデータ、それが縦に並んでいるのが配列、というイメージです。配列操作と構造体を組み合わせることで、大量の情報を効率よく処理できるようになります。
struct Point {
int x;
int y;
};
int main() {
// Point型のデータを3つ並べた配列
Point path[3] = { {0, 0}, {10, 5}, {20, 10} };
for(int i = 0; i < 3; i++) {
std::cout << "地点" << i << ": (" << path[i].x << ", " << path[i].y << ")" << std::endl;
}
return 0;
}
8. メモリ上のイメージとポインタ
構造体やクラスのオブジェクトを宣言すると、パソコンのメモリ上に、メンバ変数が順番に並んで場所を確保されます。この確保された場所の先頭を指すのがポインタです。少し発展的な内容ですが、構造体のポインタを使ってデータにアクセスするときは、ドット(.)ではなくアロー演算子(->)を使うという決まりがあります。
最初は混乱するかもしれませんが、「住所(ポインタ)から中身を見る時は矢印を使うんだな」とイメージしておくと、後の学習で非常に役立ちます。参照とポインタの理解が深まると、大きなデータを高速に処理できるようになります。
9. 独自の型を作る際のベストプラクティス
構造体やクラスの型を定義するとき、名前の付け方にはコツがあります。C++では一般的に、型名の先頭は大文字にする(例:PlayerInfo)のが慣習です。これにより、変数の名前(小文字で始めることが多い)と区別がつきやすくなり、読みやすいコードになります。
パソコンを触るのが初めての方も、まずは身の回りのものを型にしてみることから始めてみてください。「お菓子型」なら(名前、価格、カロリー)、「車型」なら(車種、色、最高速度)などです。自分の手で新しいデータ型を生み出せるようになると、プログラミングの世界が何倍にも広がりますよ!