クラス定義(メンバ変数・メンバ関数)
『C++』ではクラスを使ってデータ(メンバ変数)と操作(メンバ関数)をひとまとめにすることができます。アクセス指定子によって外部からのアクセスを制御し、thisポインタで自分自身のオブジェクトを参照できます。ここではクラスの定義からインスタンス化、getter/setter の実装まで基本的な使い方を説明します。
構文
// ========================================
// クラス定義の基本構文
// ========================================
class クラス名 {
public:
// 公開メンバ変数(外部からアクセス可能)
型 メンバ変数名;
// 公開メンバ関数(メソッド)
戻り値型 メンバ関数名(引数) {
// 処理
}
private:
// 非公開メンバ変数(クラス内部のみアクセス可能)
型 メンバ変数名;
protected:
// 保護メンバ変数(クラス自身と派生クラスからアクセス可能)
型 メンバ変数名;
};
// ========================================
// インスタンス化(オブジェクト生成)
// ========================================
// スタック上に生成します
クラス名 オブジェクト名;
// ヒープ上に生成します(ポインタ経由)
クラス名* オブジェクト名 = new クラス名();
// メンバへのアクセス
オブジェクト名.メンバ変数名
オブジェクト名.メンバ関数名(引数)
// ポインタ経由のアクセス
ポインタ名->メンバ変数名
ポインタ名->メンバ関数名(引数)
// ========================================
// this ポインタ
// ========================================
// クラス内部で自分自身のオブジェクトを参照します
this->メンバ変数名 = 値;
構文一覧
| 構文・キーワード | 概要 |
|---|---|
| class クラス名 { }; | クラスを定義します。末尾にセミコロンが必要です。 |
| public: | 以降のメンバを公開します。クラス外部からアクセスできます。 |
| private: | 以降のメンバを非公開にします。クラス内部のメンバ関数のみアクセスできます。 |
| protected: | 以降のメンバを保護します。クラス自身と継承した派生クラスからアクセスできます。 |
| this->メンバ名 | クラス内部で自分自身のオブジェクトを指すポインタです。引数名とメンバ変数名が重複する場合に区別するために使います。 |
| 戻り値型 関数名(引数) | メンバ関数を定義します。クラス内部に処理を記述します。 |
| getXxx() / setXxx() | getter はメンバ変数の値を返す関数、setter は値をセットする関数です。private なメンバへの安全なアクセスに使います。 |
| クラス名 変数名; | スタック上にオブジェクトを生成します(自動で破棄されます)。 |
| new クラス名() | ヒープ上にオブジェクトを生成します。使い終わったら delete で解放が必要です。 |
| 変数名.メンバ名 | ドット演算子でオブジェクトのメンバにアクセスします。 |
| ポインタ->メンバ名 | アロー演算子でポインタ経由のオブジェクトのメンバにアクセスします。 |
サンプルコード
fighter.cpp
// ========================================
// fighter.cpp — クラスの基本サンプルです
// ドラゴンボールの戦士を表す Fighter クラスを
// 定義してインスタンス化します
// ========================================
#include <iostream>
#include <string>
// ========================================
// Fighter クラスの定義
// ========================================
class Fighter {
private:
// private メンバ変数(外部から直接変更できません)
std::string name; // 戦士の名前です
int powerLevel; // 戦闘力です
std::string race; // 種族です
public:
// ========================================
// コンストラクタ(オブジェクト生成時に呼ばれます)
// ========================================
Fighter(std::string name, int powerLevel, std::string race) {
// this ポインタで引数名とメンバ変数名を区別します
this->name = name;
this->powerLevel = powerLevel;
this->race = race;
}
// ========================================
// getter — private メンバの値を返します
// ========================================
std::string getName() {
return this->name;
}
int getPowerLevel() {
return this->powerLevel;
}
std::string getRace() {
return this->race;
}
// ========================================
// setter — 戦闘力を更新します
// ========================================
void setPowerLevel(int powerLevel) {
if (powerLevel < 0) {
std::cout << "戦闘力に負の値は設定できません。" << std::endl;
return;
}
this->powerLevel = powerLevel;
}
// ========================================
// メンバ関数 — 戦士の情報を表示します
// ========================================
void showInfo() {
std::cout << "名前: " << this->name << std::endl;
std::cout << "戦闘力: " << this->powerLevel << std::endl;
std::cout << "種族: " << this->race << std::endl;
std::cout << "----------------------------" << std::endl;
}
// ========================================
// メンバ関数 — 相手と戦闘力を比較します
// ========================================
void battle(Fighter& opponent) {
std::cout << this->name << " vs " << opponent.getName() << std::endl;
if (this->powerLevel > opponent.getPowerLevel()) {
std::cout << this->name << " の勝利です!" << std::endl;
} else if (this->powerLevel < opponent.getPowerLevel()) {
std::cout << opponent.getName() << " の勝利です!" << std::endl;
} else {
std::cout << "引き分けです!" << std::endl;
}
std::cout << "----------------------------" << std::endl;
}
};
// ========================================
// main 関数
// ========================================
int main() {
// スタック上に Fighter オブジェクトを生成します
Fighter goku("孫悟空", 9000, "サイヤ人");
Fighter vegeta("ベジータ", 8000, "サイヤ人");
Fighter piccolo("ピッコロ", 3500, "ナメック星人");
// メンバ関数で情報を表示します
std::cout << "=== 戦士一覧 ===" << std::endl;
goku.showInfo();
vegeta.showInfo();
piccolo.showInfo();
// setter で戦闘力を更新します
std::cout << "=== 修行後の戦闘力更新 ===" << std::endl;
vegeta.setPowerLevel(9500);
std::cout << "ベジータの戦闘力: " << vegeta.getPowerLevel() << std::endl;
std::cout << "----------------------------" << std::endl;
// バトルを実行します
std::cout << "=== バトル ===" << std::endl;
goku.battle(vegeta);
goku.battle(piccolo);
// ヒープ上に生成する場合は new を使います
Fighter* krillin = new Fighter("クリリン", 1770, "人間");
std::cout << "=== ポインタ経由のアクセス ===" << std::endl;
krillin->showInfo();
// ヒープ上のオブジェクトは必ず delete で解放します
delete krillin;
return 0;
}
# g++ でコンパイルします(-std=c++17 で C++17 規格を指定) g++ -std=c++17 fighter.cpp -o fighter # 実行します(macOS / Linux) ./fighter === 戦士一覧 === 名前: 孫悟空 戦闘力: 9000 種族: サイヤ人 ---------------------------- 名前: ベジータ 戦闘力: 8000 種族: サイヤ人 ---------------------------- 名前: ピッコロ 戦闘力: 3500 種族: ナメック星人 ---------------------------- === 修行後の戦闘力更新 === ベジータの戦闘力: 9500 ---------------------------- === バトル === 孫悟空 vs ベジータ ベジータ の勝利です! ---------------------------- 孫悟空 vs ピッコロ 孫悟空 の勝利です! ---------------------------- === ポインタ経由のアクセス === 名前: クリリン 戦闘力: 1770 種族: 人間 ----------------------------
よくあるミス: new で確保したオブジェクトの delete 忘れ
new で確保したオブジェクトは delete で解放しないとメモリリークが発生します。スタックに確保した場合はスコープを抜けると自動解放されます。
// NG: delete を忘れるとメモリリークが発生する
void createFighter() {
Fighter* krillin = new Fighter("クリリン", 1770, "人間");
krillin->showInfo();
// delete krillin; が抜けている → メモリリーク
}
OK: new で確保したオブジェクトは必ず delete で解放します。
// OK: delete で解放する
void createFighter() {
Fighter* krillin = new Fighter("クリリン", 1770, "人間");
krillin->showInfo();
delete krillin; // 必ず解放します
}
g++ -std=c++17 ok_example.cpp -o ok_example ./ok_example 名前: クリリン 戦闘力: 1770 種族: 人間
よくあるミス: クラス定義末尾のセミコロン忘れ
C++ のクラス定義は末尾にセミコロンが必要です。忘れるとコンパイルエラーになります。
// NG: セミコロンなし
class Fighter {
public:
std::string name;
} // error: expected ';' after class definition
OK: クラス定義の閉じ括弧の後にセミコロンを付けます。
// OK: 末尾にセミコロンを付ける
class Fighter {
public:
std::string name;
}; // セミコロンが必要
概要
クラスは class キーワードで定義し、末尾にセミコロンが必要です。メンバ変数を private にして外部から直接変更できないようにし、getter と setter を通じてアクセスさせる設計は「カプセル化」と呼ばれ、C++ における重要なオブジェクト指向の原則のひとつです。public にしたメンバはクラス外部から自由にアクセスでき、protected は継承した派生クラスからも参照できます。this ポインタはコンストラクタやメンバ関数の引数名がメンバ変数名と同じときに特に役立ちます。オブジェクトのメモリはスタック(変数宣言)かヒープ(new)に確保でき、ヒープに確保した場合は delete で解放します。スタックに確保した場合はスコープを抜けると自動的に解放されます。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。