【C++】構造体(struct)とクラス(class)の違いとは?|どっちを使えばいい?

サムネイル画像 C++

struct Player { int hp; };とclass Player { int hp; };。ほとんど同じに見えるこの2つは、hpを外から触れるかどうかが、違います。

この記事では、structとclassの違いを、デフォルトのアクセス修飾子から整理して、どちらを使うべきか、どう使い分けるかを解説します。

structとclassの違いとは?

結論から言うと、C++の struct と class は、機能面ではかなり似ています。

実は、どちらもメンバ変数を持てますし、メンバ関数も書けますし、コンストラクタも定義できます。つまり、初心者が思いがちな「structはただの変数の集まりで、classだけが本格機能を持つ」という理解は少し違います。

主な違いは、次の2つです。

  • struct はメンバのデフォルトアクセスが public
  • class はメンバのデフォルトアクセスが private

さらに継承を書く時も、struct はデフォルトで public 継承、class はデフォルトで private 継承になります。ただ、初心者の段階ではまずメンバのデフォルトアクセスの違いを押さえれば十分です。

なぜ違いを知る必要がある?

違いを知っておく必要があるのは、コードの意図を伝えやすくなるからです。

たとえば、座標や色のように単純なデータをまとめたいだけなら struct がかなり自然です。一方で、HPを勝手にマイナスにされたくない、外から直接触らせたくない、といったルールを持たせたい設計なら class の方が向いています。

クラスそのものの基本を先に整理したい方は、クラスの記事もあわせて読むと理解しやすいです。

まずはコードで違いを見てみよう

まずは、デフォルトアクセスの違いが一番わかりやすい例を見てみましょう。

▼main.cpp


#include <iostream>

struct PlayerStruct {
    int hp = 100;
};

class PlayerClass {
    int hp = 100;
};

int main() {
    PlayerStruct a;
    std::cout << "PlayerStruct.hp: " << a.hp << "\n";

    PlayerClass b;
    // std::cout << b.hp << "\n"; // これはエラー

    return 0;
}

実行結果

PlayerStruct.hp: 100

struct では何も書かなくても hp が外から見えますが、class では何も書かないと private 扱いになるので、そのままでは外からアクセスできません。

structでも関数は書ける

ここで初心者がかなり勘違いしやすいのですが、structにも関数は書けます。

▼main.cpp


#include <iostream>

struct Vec2 {
    float x;
    float y;

    void Print() const {
        std::cout << "x: " << x << ", y: " << y << "\n";
    }
};

int main() {
    Vec2 pos = {10.0f, 20.0f};
    pos.Print();
    return 0;
}

実行結果

x: 10, y: 20

このように、struct だからといって「関数を書けない」「簡易版class」というわけではありません。違いはあくまで、デフォルトの見え方のほうが本質です。

どっちを使えばいい?

結論としては、次のように考えるとかなり分かりやすいです。

  • struct:座標、色、設定値など、単純なデータのまとまり
  • class:状態管理やルールを持たせたい、外から勝手に触らせたくない設計

たとえば、ゲーム制作なら Vec2、Color、Rect のようなものは struct でかなり自然です。一方で、プレイヤーや敵キャラのように「HPは0未満にしない」「ダメージ処理は専用関数を通す」などのルールがあるものは class の方が向いています。

実際、ポインタや参照と組み合わせてオブジェクトを扱う場面では、ポインタの記事の内容ともかなりつながってきます。

実践例

では、struct と class をそれぞれ自然な場面で使った例を見てみましょう。

▼main.cpp


#include <iostream>

struct Vec2 {
    float x;
    float y;
};

class Player {
public:
    Player(int hp, Vec2 pos) : m_hp(hp), m_pos(pos) {}

    void TakeDamage(int damage) {
        m_hp -= damage;
        if (m_hp < 0) {
            m_hp = 0;
        }
    }

    void PrintStatus() const {
        std::cout << "HP: " << m_hp
                  << ", Pos(" << m_pos.x << ", " << m_pos.y << ")\n";
    }

private:
    int m_hp;
    Vec2 m_pos;
};

int main() {
    Vec2 startPos = {100.0f, 200.0f};
    Player player(100, startPos);

    player.PrintStatus();
    player.TakeDamage(30);
    player.PrintStatus();

    return 0;
}

実行結果

HP: 100, Pos(100, 200)
HP: 70, Pos(100, 200)

この例では、座標はただのデータなので struct、プレイヤーはダメージ処理やHP管理のルールを持つので class にしています。こうすると、役割の違いがかなり見えやすくなります。

【重要】私が実際にstructとclassで困った体験談

私も自主制作で最初の頃は、とりあえず全部structで書いてしまうことがありました。

最初は書きやすいので問題ないように見えたのですが、敵キャラのHPや状態フラグまで全部publicのまま置いていたので、別の処理から気軽に値を書き換えられてしまい、「どこで値が壊れたのか分からない」状態になったことがあります。

特に、ダメージ処理のはずなのに別の場所で直接 hp = -50 のような代入が起きていて、バグの原因を追うのにかなり時間がかかりました。

そこで、単純な座標や設定値だけを struct にして、状態管理が必要なものは class に分けるようにしたところ、コードがかなり整理されました。これで、「とりあえず全部struct」でも「全部class」でもなく、役割で分けるのが大事だと実感しました。

こういう設計のズレは、コード量が増えるほど気づきにくくなります。変数の変化を追う時は、C++でのデバッグのやり方の記事もかなり参考になります。

structとclass使用時のよくある失敗例と対処法

  • structは関数を書けないと思ってしまう
    struct にもメンバ関数やコンストラクタは書けます。違いは主にデフォルトアクセスです。
  • classにしたのにpublicを書き忘れる
    class は何も書かないと private です。外から使う関数は public: の下に書きましょう。
  • 全部どちらか一方に統一しようとしてしまう
    大事なのは統一よりも役割です。単純データなら struct、隠したい状態やルールがあるなら class と考えると整理しやすいです。

注意点

  • struct と class は見た目ほど別物ではありません
  • 違いは「機能の有無」よりも「デフォルトアクセス」と「設計意図」にあります
  • 初心者のうちは、まず「データだけならstruct」「管理したいならclass」で考えるとかなり分かりやすいです

また、ヘッダーファイルに分けて書く時は、#includeの””と<>の違いの記事もあわせて読むと、複数ファイル構成が理解しやすくなります。

まとめ

  • struct と class は、C++では機能面がかなり似ている
  • 大きな違いは、structはデフォルトでpublic、classはデフォルトでprivate という点
  • 単純なデータのまとまりには struct が向いている
  • 状態管理やルールを持たせたいものには class が向いている
  • 「どっちが上か」ではなく、役割で使い分けるのが大切

structはデフォルトでpublic、classはデフォルトでprivateです。この違いを基準に、「外から自由に触っていいデータ」ならstruct、「ルールを守って操作させたいもの」ならclassと、役割で使い分けます。

関連記事