C++: C++ 継承
最終更新:2026-08-31
StudentクラスとTeacherクラスを書くとき、どちらもnameとageを持ちます。同じコードを何度も書くのは面倒です。
Personクラスのコードを再利用できませんか?継承で解決 —— クラス間で「親子」関係を作ります。
1. 継承とは?
(1) 1.1 継承の概念
| 概念 | プログラムでの意味 |
|---|---|
| 継承(親クラスのメンバーを引き継ぐ) | 派生クラスが基底クラスのメンバーを継承 |
| 追加(派生クラス独自のメンバー) | 派生クラスが独自のメンバーを追加 |
継承の目的: あるクラスのコードを、別のクラスで再利用。
(2) 1.2 なぜ継承が必要?
継承を使わない場合(コード重複):
▶ サンプル 2:コード例(難易度 ⭐)
CPP
#include <iostream>
#include <string>
// Studentクラス
class Student {
std::string name;
int age;
std::string studentId;
};
// Teacherクラス
class Teacher {
std::string name; // ❌ 重複
int age; // ❌ 重複
std::string teacherId;
};
継承を使う場合(コード再利用):
CPP
#include <iostream>
#include <string>
// 基底クラス(親)
class Person {
public:
std::string name;
int age;
};
// 派生クラス(子)
class Student : public Person {
public:
std::string studentId; // 追加メンバー
};
class Teacher : public Person {
public:
std::string teacherId; // 追加メンバー
};
2. 継承の基本
(1) 2.1 派生クラスの宣言
構文:
TEXT
📖 参照専用
class 派生クラス : 継承方式 基底クラス {
// ...
};
例:
CPP
#include <iostream>
#include <string>
class Person {
public:
std::string name;
int age;
};
// StudentがPersonを継承
class Student : public Person {
public:
std::string studentId;
};
int main() {
Student s1;
s1.name = "Alice"; // ✅ 継承したname
s1.age = 20; // ✅ 継承したage
s1.studentId = "2024001"; // 独自メンバー
std::cout << "名前:" << s1.name << std::endl;
std::cout << "年齢:" << s1.age << std::endl;
std::cout << "学籍番号:" << s1.studentId << std::endl;
return 0;
}
3. 継承のアクセス制御
(1) 3.1 継承方式
| 基底クラスのメンバー \ 継承方式 | public継承 | protected継承 | private継承 |
|---|---|---|---|
| publicメンバー | public(公開) | protected | private |
| protectedメンバー | protected | protected | private |
| privateメンバー | アクセス不可 | アクセス不可 | アクセス不可 |
💡 推奨: ほとんどの場合は
public 継承を使います。
(2) 3.2 public継承(最も一般的)
CPP
#include <iostream>
#include <string>
class Person {
private:
std::string id; // private:派生クラスからアクセス不可
protected:
std::string address; // protected:派生クラスからアクセス可
public:
std::string name; // public:どこからでもアクセス可
void introduce() {
std::cout << "私は" << name << "です" << std::endl;
}
};
class Student : public Person {
public:
void setAddress(const std::string& addr) {
address = addr; // ✅ protectedはアクセス可
// id = "123"; // ❌ privateはアクセス不可
}
};
int main() {
Student s1;
s1.name = "Alice"; // ✅ publicはアクセス可
// s1.address = "東京"; // ❌ protectedは外部からアクセス不可
return 0;
}
4. コンストラクタと継承
(1) 4.1 派生クラスのコンストラクタ呼び出し順序
ルール: まず基底クラスのコンストラクタを呼び出し、その後派生クラスのコンストラクタを呼び出す。
CPP
#include <iostream>
#include <string>
class Person {
public:
Person() {
std::cout << "Personのコンストラクタ" << std::endl;
}
};
class Student : public Person {
public:
Student() {
std::cout << "Studentのコンストラクタ" << std::endl;
}
};
int main() {
Student s1;
return 0;
}
出力:
TEXT 📖 参照専用Personのコンストラクタ Studentのコンストラクタ
💡 ヒント: デストラクタの呼び出し順序は逆 —— まず派生クラスのデストラクタ、その後基底クラスのデストラクタ。
5. 実践例:学生管理システム(継承)
▶ サンプル 1:継承を使った実装(難易度 ⭐⭐)
CPP
#include <iostream>
#include <string>
// 基底クラス
class Person {
protected:
std::string name;
int age;
public:
Person(const std::string& n, int a) : name(n), age(a) {}
void introduce() {
std::cout << "名前:" << name << "、年齢:" << age << std::endl;
}
};
// 派生クラス
class Student : public Person {
private:
std::string studentId;
double score;
public:
Student(const std::string& n, int a, const std::string& id, double s)
: Person(n, a), studentId(id), score(s) {}
void introduce() {
Person::introduce(); // 基底クラスのintroduceを呼び出し
std::cout << "学籍番号:" << studentId << "、点数:" << score << std::endl;
}
};
int main() {
Student s1("Alice", 20, "2024001", 92.5);
s1.introduce();
return 0;
}
出力:
TEXT 📖 参照専用名前:Alice、年齢:20 学籍番号:2024001、点数:92.5
▶ サンプル 3:多段継承(難易度 ⭐⭐)
CPP
#include <iostream>
#include <string>
class Animal {
public:
std::string name;
void eat() { std::cout << name << "は食べている" << std::endl; }
};
class Mammal : public Animal {
public:
void breathe() { std::cout << name << "は空気を吸っている" << std::endl; }
};
class Dog : public Mammal {
public:
void bark() { std::cout << name << "が吠える:ワン!" << std::endl; }
};
int main() {
Dog myDog;
myDog.name = "Buddy";
myDog.eat(); // Animalから継承
myDog.breathe(); // Mammalから継承
myDog.bark(); // Dogで定義
return 0;
}
出力:
TEXT 📖 参照専用Buddyは食べている Buddyは空気を吸っている Buddyが吠える:ワン!
❓ よくある質問
Q 継承方式はどれを使う?
A
public継承:最も一般的、基底クラスのインターフェースをそのまま公開protected継承:まれに使うprivate継承:まれに使う
推奨:
📖 まとめ
- 継承は派生クラスが基底クラスのコードを再利用
- public継承が最も一般的
- 派生クラスはアクセスできない:基底クラスの
privateメンバー - 派生クラスはアクセスできる:基底クラスの
protectedメンバー - コンストラクタ呼び出し順序:基底クラス → 派生クラス
📝 練習問題
-
初級(難易度 ⭐):
Animal基底クラスを定義し、nameメンバーを持たせてください。DogとCatクラスを継承。 -
中級(難易度 ⭐⭐): 上のプログラムを改良し、
Animalにvoid speak()仮想関数を追加、DogとCatでオーバーライド。 -
上級(難易度 ⭐⭐⭐): 図書管理システムのクラスを設計:
Person(名前、年齢)StudentがPersonを継承(学籍番号、点数)TeacherがPersonを継承(教員番号、学科)- 検索と表示機能を実装。
6. 🚀 次のステップ
継承を理解したら、次は ポリモーフィズム(レッスン32) —— 基底クラスのポインタで派生クラスの関数を呼び出し、「インターフェース、多様な実装」を実現しよう!