my.code(); Logomy.code();
C++-6.クラスの基礎

my.code(); Logomy.code();

  • C++
    • 0.C++の世界へようこそ
    • 1.型システムと制御構造
    • 2.データ集合とモダンな操作
    • 3.ポインタとメモリ管理
    • 4.関数と参照渡し
    • 5.プロジェクトの分割とビルド
    • 6.クラスの基礎
    • 7.クラスを使いこなす
    • 8.継承とポリモーフィズム
    • 9.テンプレート
    • 10.STL ①:コンテナ
    • 11.STL ②:アルゴリズムとラムダ式
    • 12.RAIIとスマートポインタ
  • JavaScript
    • 0.JavaScriptへようこそ
    • 1.基本構文とデータ型
    • 2.制御構文
    • 3.関数とクロージャ
    • 4.'this'の正体
    • 5.オブジェクトとプロトタイプ
    • 6.クラス構文
    • 7.配列とイテレーション
    • 8.非同期処理①: Promise
    • 9.非同期処理②: Async/Await
  • Python
    • 0.環境構築と基本思想
    • 1.基本構文とデータ型
    • 2.リスト、タプル、辞書、セット
    • 3.制御構文と関数
    • 4.モジュールとパッケージ
    • 5.オブジェクト指向プログラミング
    • 6.ファイルの入出力とコンテキストマネージャ
    • 7.例外処理
    • 8.ジェネレータとデコレータ
  • Ruby
    • 0.rubyの世界へようこそ
    • 1.基本構文とデータ型
    • 2.制御構造とメソッド定義
    • 3.すべてがオブジェクト
    • 4.コレクション (Array, Hash, Range)
    • 5.ブロックとイテレータ
    • 6.クラスとオブジェクト
    • 7.モジュールとMix-in
    • 8.Proc, Lambda, クロージャ
    • 9.標準ライブラリの活用
    • 10.テスト文化入門
    • 11.メタプログラミング入門
  • Rust
    • 0.Rustの世界へようこそ
    • 1.基本構文と「不変性」
    • 2.関数と制御フロー
    • 3.所有権
    • 4.借用とスライス
    • 5.構造体とメソッド構文
    • 6.列挙型とパターンマッチ
    • 7.モジュールシステムとパッケージ管理
    • 8.コレクションと文字列
    • 9.エラーハンドリング
    • 10.ジェネリクスとトレイト
    • 11.ライフタイム
  • TypeScript
    • 0.TypeScriptへようこそ
    • 1.基本的な型と型推論
    • 2.オブジェクト、インターフェース、型エイリアス
    • 3.関数の型定義
    • 4.型を組み合わせる
    • 5.ジェネリクス
    • 6.クラスとアクセス修飾子
    • 7.非同期処理とユーティリティ型
my.code(); Logomy.code();

環境構築不要、その場で実践。

ut-code / my-code

Copyright © 2026 ut.code();

my.code(); について
コード実行環境についてAI質問機能についてライセンスお問い合わせ
ut.code(); について
公式ウェブサイト公式 𝕏 アカウント

第6章: オブジェクト指向の入口:クラスの基礎

これまでの章では、C++の基本的な文法やメモリの扱い方について学んできました。この章からは、C++の最も強力な機能の一つであるオブジェクト指向プログラミング (Object-Oriented Programming, OOP) の世界に足を踏み入れます。OOPの考え方を身につけることで、より大規模で複雑なプログラムを、現実世界の「モノ」の概念に近い形で、直感的に設計・実装できるようになります。その第一歩として、OOPの中核をなすクラスの基礎を学びましょう。

クラスとは?: データ(メンバ変数)と処理(メンバ関数)のカプセル化

他のプログラミング言語でオブジェクト指向に触れたことがあるなら、「クラスはオブジェクトの設計図」という説明を聞いたことがあるかもしれません。C++でもその考え方は同じです。クラスは、ある「モノ」が持つべきデータ(属性)と、そのデータに対する処理(操作)を一つにまとめたものです。

  • データ(属性): クラス内に定義された変数のことで、メンバ変数 (member variables) またはデータメンバと呼びます。
  • 処理(操作): クラス内に定義された関数のことで、メンバ関数 (member functions) またはメソッドと呼びます。

このように、関連するデータと処理を一つのクラスにまとめることを、OOPの重要な概念の一つであるカプセル化 (encapsulation) と呼びます。💊

例として、「人」を表すPersonクラスを考えてみましょう。「人」は「名前」や「年齢」といったデータ(メンバ変数)を持ち、「自己紹介する」といった処理(メンバ関数)を行うことができます。

class Person {
public:
    // メンバ変数
    std::string name;
    int age;

    // メンバ関数
    void introduce() {
        std::cout << "My name is " << name << ", and I am " << age << " years old." << std::endl;
    }
};

class Person { ... }; という構文でクラスを定義します。クラス定義の最後にはセミコロン;が必要なので忘れないようにしましょう。現時点では、public:というキーワードは「これらのメンバは外部からアクセスできます」という意味だと考えておいてください。詳細は後ほど説明します。

インスタンスの生成: クラスからオブジェクトを作ってみる

クラスはあくまで「設計図」です。実際にプログラムで利用するためには、この設計図をもとに実体を作る必要があります。クラスから作られた実体のことをオブジェクト (object) またはインスタンス (instance) と呼び、オブジェクトを作ることをインスタンス化 (instantiation) と言います。

インスタンス化の構文は、変数の宣言とよく似ています。

ファイルを編集:instantiation.cpp
#include <iostream>
#include <string>

// Personクラスの定義
class Person {
public:
    std::string name;
    int age;

    void introduce() {
        std::cout << "My name is " << name << ", and I am " << age << " years old." << std::endl;
    }
};

int main() {
    // Personクラスのインスタンスを生成
    Person taro;

    // メンバ変数に値を代入 (ドット演算子 . を使用)
    taro.name = "Taro";
    taro.age = 30;

    // メンバ関数を呼び出す
    taro.introduce(); // "My name is Taro, and I am 30 years old." と出力される

    // 別のインスタンスを生成
    Person hanako;
    hanako.name = "Hanako";
    hanako.age = 25;
    hanako.introduce(); // "My name is Hanako, and I am 25 years old." と出力される

    return 0;
}
ブラウザ上で動作するcppの実行環境です。
左上の実行ボタンを押して、このページ内のinstantiation.cppに書かれている内容を実行します。
My name is Taro, and I am 30 years old.
My name is Hanako, and I am 25 years old.

このように、クラス名 インスタンス名; という形でインスタンスを生成できます。インスタンスのメンバ変数やメンバ関数にアクセスするには、インスタンス名.メンバ名 のようにドット演算子 (.) を使います。taroとhanakoは同じPersonクラスから作られたインスタンスですが、それぞれが独立したデータを持っていることがわかります。

アクセス制御: public と private による情報の隠蔽

先ほどのPersonクラスの例では、main関数からtaro.age = 30;のようにメンバ変数に直接アクセスできました。これは手軽ですが、問題を引き起こす可能性があります。例えば、年齢にマイナスの値や非現実的な値を設定できてしまうかもしれません。

Person jiro;
jiro.name = "Jiro";
jiro.age = -5; // 本来ありえない値が設定できてしまう!
jiro.introduce();

このような意図しない操作を防ぐために、C++にはアクセス制御の仕組みがあります。クラスのメンバは、外部からのアクセスの可否を指定できます。

  • public: クラスの外部(main関数など)から自由にアクセスできます。
  • private: そのクラスのメンバ関数からしかアクセスできません。外部からはアクセス不可です。

アクセス制御の基本は、メンバ変数はprivateにし、メンバ関数はpublicにすることです。これにより、データの不正な書き換えを防ぎ、クラスの内部実装を外部から隠蔽します。これを情報の隠蔽 (information hiding) と呼び、カプセル化の重要な目的の一つです。

privateなメンバ変数に安全にアクセスするために、publicなメンバ関数(ゲッターやセッターと呼ばれる)を用意するのが一般的です。

ファイルを編集:access_control.cpp
#include <iostream>
#include <string>

class Person {
private:
    // メンバ変数は外部から隠蔽する
    std::string name;
    int age;

public:
    // セッター: メンバ変数に値を設定する
    void setName(const std::string& newName) {
        name = newName;
    }

    void setAge(int newAge) {
        if (newAge >= 0 && newAge < 150) { // 不正な値をチェック
            age = newAge;
        } else {
            std::cout << "Error: Invalid age value." << std::endl;
        }
    }

    // ゲッター: メンバ変数の値を取得する
    std::string getName() const {
        return name;
    }

    int getAge() const {
        return age;
    }

    // このメンバ関数はクラス内部にあるので、privateメンバにアクセスできる
    void introduce() {
        std::cout << "My name is " << name << ", and I am " << age << " years old." << std::endl;
    }
};

int main() {
    Person saburo;

    // saburo.name = "Saburo"; // エラー! privateメンバには直接アクセスできない
    // saburo.age = -10;       // エラー!

    // publicなメンバ関数を経由して安全に値を設定
    saburo.setName("Saburo");
    saburo.setAge(28);

    saburo.introduce();

    saburo.setAge(-10); // エラーメッセージが出力される

    // publicなメンバ関数経由で値を取得
    std::cout << "Name: " << saburo.getName() << std::endl;

    return 0;
}
ブラウザ上で動作するcppの実行環境です。
左上の実行ボタンを押して、このページ内のaccess_control.cppに書かれている内容を実行します。
My name is Saburo, and I am 28 years old.
Error: Invalid age value.
Name: Saburo

setAge関数内で値の妥当性チェックを行っている点に注目してください。このように、クラスの利用者は内部の実装を気にすることなく、提供されたpublicなインターフェース(メンバ関数)を通じて安全にオブジェクトを操作できます。

constキーワード: getName() const のようにメンバ関数の後ろにconstを付けると、その関数がメンバ変数を変更しないことをコンパイラに約束します。このような関数をconstメンバ関数と呼びます。

コンストラクタとデストラクタ: オブジェクトが生まれてから消えるまで

オブジェクトは生成され、利用され、やがて破棄されます。このライフサイクルに合わせて特別な処理を自動的に実行するための仕組みがコンストラクタとデストラクタです。

コンストラクタ (Constructor)

コンストラクタは、インスタンスが生成されるときに自動的に呼び出される特別なメンバ関数です。主な役割は、メンバ変数の初期化です。

コンストラクタには以下の特徴があります。

  • 関数名がクラス名と全く同じ。
  • 戻り値の型を指定しない(voidも付けない)。
  • 引数を取ることができ、複数定義できる(オーバーロード)。
ファイルを編集:constructor.cpp
class Person {
private:
    std::string name;
    int age;

public:
    // 引数付きコンストラクタ
    Person(const std::string& initName, int initAge) {
        std::cout << "Constructor called for " << initName << std::endl;
        name = initName;
        age = initAge;
    }
    // ...
};

int main() {
    // インスタンス生成時にコンストラクタが呼ばれ、引数が渡される
    Person yuko("Yuko", 22); // この時点でコンストラクタが実行される
    yuko.introduce();
}
ブラウザ上で動作するcppの実行環境です。
左上の実行ボタンを押して、このページ内のconstructor.cppに書かれている内容を実行します。
Constructor called for Yuko
My name is Yuko, and I am 22 years old.

このように、インスタンス生成時に()で初期値を渡すことで、オブジェクトを生成と同時に有効な状態にできます。set関数を別途呼び出す手間が省け、初期化忘れを防ぐことができます。

デストラクタ (Destructor)

デストラクタは、インスタンスが破棄されるとき(例えば、変数のスコープを抜けるとき)に自動的に呼び出される特別なメンバ関数です。主な役割は、オブジェクトが使用していたリソース(メモリやファイルなど)の後片付けです。

デストラクタには以下の特徴があります。

  • 関数名が ~ + クラス名。
  • 戻り値も引数も取らない。
  • 1つのクラスに1つしか定義できない。
ファイルを編集:constructor_destructor.cpp
#include <iostream>
#include <string>

class Person {
private:
    std::string name;
    int age;

public:
    // コンストラクタ
    Person(const std::string& initName, int initAge) {
        std::cout << "Constructor called for " << initName << "." << std::endl;
        name = initName;
        age = initAge;
    }

    // デストラクタ
    ~Person() {
        std::cout << "Destructor called for " << name << "." << std::endl;
    }

    void introduce() {
        std::cout << "My name is " << name << ", and I am " << age << " years old." << std::endl;
    }
};

void create_person_scope() {
    std::cout << "--- Entering scope ---" << std::endl;
    Person kenji("Kenji", 45); // kenjiはこのスコープ内でのみ生存
    kenji.introduce();
    std::cout << "--- Exiting scope ---" << std::endl;
} // ここでkenjiのスコープが終わり、デストラクタが呼ばれる

int main() {
    create_person_scope();

    std::cout << "--- Back in main ---" << std::endl;

    return 0;
}
ブラウザ上で動作するcppの実行環境です。
左上の実行ボタンを押して、このページ内のconstructor_destructor.cppに書かれている内容を実行します。
--- Entering scope ---
Constructor called for Kenji.
My name is Kenji, and I am 45 years old.
--- Exiting scope ---
Destructor called for Kenji.
--- Back in main ---

実行結果を見ると、kenjiオブジェクトが生成されたときにコンストラクタが、create_person_scope関数のスコープを抜けるときにデストラクタが自動的に呼び出されていることがわかります。動的に確保したメモリの解放など、クリーンアップ処理はデストラクタに書くのが定石です。この考え方は、今後の章で学ぶRAII(Resource Acquisition Is Initialization)という重要な概念に繋がります。

この章のまとめ

この章では、C++におけるオブジェクト指向プログラミングの第一歩として、クラスの基本的な概念を学びました。

  • クラスは、データ(メンバ変数)と処理(メンバ関数)を一つにまとめた「設計図」です。
  • クラスから実体であるオブジェクト(インスタンス)を生成して使用します。
  • カプセル化は、関連するデータと処理をまとめることです。
  • アクセス制御(public, private)により、外部からアクセスされたくないメンバを保護します(情報の隠蔽)。
  • コンストラクタは、オブジェクト生成時に自動で呼ばれ、初期化を行います。
  • デストラクタは、オブジェクト破棄時に自動で呼ばれ、後片付けを行います。

クラスを使いこなすことで、プログラムの部品化が進み、再利用性やメンテナンス性が格段に向上します。次の章では、クラスのさらに進んだ機能について学んでいきましょう。

練習問題1: 長方形クラス

幅(width)と高さ(height)をメンバ変数として持つRectangleクラスを作成してください。

  • メンバ変数はprivateで定義してください。
  • コンストラクタで幅と高さを初期化できるようにしてください。
  • 面積を計算して返すgetArea()メソッドと、周の長さを計算して返すgetPerimeter()メソッドをpublicで実装してください。
  • main関数でRectangleクラスのインスタンスをいくつか生成し、面積と周の長さを表示するプログラムを作成してください。
ファイルを編集:practice7_1.cpp
#include <iostream>
#include <string>
// ここにRectangleクラスを定義してください

int main() {
    // ここでRectangleクラスのインスタンスを生成し、面積と周の長さを表示してください

    return 0;
}
ブラウザ上で動作するcppの実行環境です。
左上の実行ボタンを押して、このページ内のpractice7_1.cppに書かれている内容を実行します。

練習問題2: 書籍クラス

タイトル(title)、著者(author)、ページ数(pages)をメンバ変数として持つBookクラスを作成してください。

  • メンバ変数はprivateで定義してください。
  • コンストラクタで、タイトル、著者、ページ数を初期化できるようにしてください。
  • 本の情報を整形してコンソールに出力するprintInfo()メソッドをpublicで実装してください。(例: Title: [タイトル], Author: [著者], Pages: [ページ数] pages)
  • main関数でBookクラスのインスタンスを生成し、その情報を表示してください。
ファイルを編集:practice7_2.cpp
#include <iostream>
#include <string>
// ここにBookクラスを定義してください

int main() {
    // ここでBookクラスのインスタンスを生成し、情報を表示してください

    return 0;
}
ブラウザ上で動作するcppの実行環境です。
左上の実行ボタンを押して、このページ内のpractice7_2.cppに書かれている内容を実行します。
Title: The Great Gatsby, Author: F. Scott Fitzgerald, Pages: 180 pages
前のページ« プロジェクトの分割とビルド
次のページクラスを使いこなす »