C++における継承
[仮にあなたが]
Studentクラス[と]Teacherクラスを記述したとすると、[これらにはどちらも「氏名」]と[「年齢」]があるが、[学生には「学生番号」]があり、[教師には「職員番号」]があることがわかる。
Personクラスのコードを[再利用][できるか]?継承[はまさにそのためのもの]――[クラス][同士に]「[親子]」[関係]を[形成]させるためだ。
1. 継承とは何か?
(1) 1.1 [日常生活における]相続
| [生活シーン] | 番組[での対応] |
|---|---|
| [子]の継承[親の特徴]([目の色]、[身長など]) | 派生クラスの継承基底クラスのメンバ |
| [子どもにはそれぞれ独自の特徴がある]([特技など]) | 派生クラス[に新しい]メンバを追加できる |
継承[の本質]: [既存の]クラス[を基に]、[拡張]して[新しい]クラスを作成すること。
(2) 1.2 なぜ継承が必要なのか?
[不要]継承([重複]コード):
▶ サンプル 2: codeexample (難易度 ⭐)
#include iostream
#include string
// ...
class Student {
std::string name;
int age;
std::string studentId;
};
// ...
class Teacher {
std::string name; // ❌
int age; // ❌
std::string teacherId;
};
[利用]継承(コード[再利用]):
#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 派生クラスの宣言
[文法]:
class : {
// ...
};
例:
#include iostream
#include string
class Person {
public:
std::string name;
int age;
};
// Student inheritance Person
class Student : public Person {
public:
std::string studentId;
};
int main() {
Student s1;
s1.name = "Alice"; // ✅ inheritance name
s1.age = 20; // ✅ inheritance 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 [3種類の]相続[方式]
| 基底クラスのメンバ \ 継承[方式] | パブリック継承 | プロテクト継承 | プライベート継承 |
|---|---|---|---|
| パブリックメンバー | パブリック([不変]) | プロテクト | プライベート |
| protected メンバー | protected | protected | private |
| プライベートメンバー | [アクセス不可] | [アクセス不可] | [アクセス不可] |
💡 [要点]: [最もよく使われる]継承[の方法は] public 継承です。
(2) 3.2 パブリック継承([おすすめ])
#include iostream
#include string
class Person {
private:
std::string id; //:
protected:
std::string address; //:
public:
std::string name; //:
void introduce() {
std::cout << "My name is" << name << std::endl;
}
};
class Student : public Person {
public:
void setAddress(const std::string& addr) {
address = addr; // ✅
// id = "123"; // ❌ Yes
}
};
int main() {
Student s1;
s1.name = "Alice"; // ✅
// s1.address = "Wuhan"; // ❌ (protected)
return 0;
}
4. コンストラクタと継承
(1) 4.1 派生クラスのコンストラクタ[の呼び出し順序]
[ルール]: [まず]基底クラスのコンストラクタを呼び出し、[その後]派生クラスのコンストラクタを呼び出す。
#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;
}
出力:
Person
Student
💡 [要点]: デストラクタの[呼び出し順序]は[逆]——[まず]派生クラスのデストラクタが呼び出され、[その後]基底クラスのデストラクタが呼び出される。
5. 演習:[シンプルな学生管理システム](継承[版])
▶ サンプル 1: [用]継承[の実現] (難易度 ⭐⭐)
#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;
}
出力:
❓ よくある質問
public 継承:[最も一般的],[基底クラスの]インターフェースを[変更せずに]維持 > - protected 継承:[あまり使われない] > - private 継承:[あまり使われない]📖 まとめ
- 継承[による]派生クラス[による]基底クラス[の]コードの[再利用]
- 公開継承[最もよく使われる]
- 派生クラス[アクセス不可]基底クラス[の]
privateメンバ - 派生クラス[アクセス可能]基底クラス[の]
protectedメンバ - コンストラクタ[呼び出し順序]:基底クラス → 派生クラス
📝 練習問題
-
初心者(難易度 ⭐): [定義する]
Animal基底クラス。[これには]nameメンバが含まれる。[そして]Dog[と]Catクラスが[これ]を継承するようにする。 -
中級(難易度 ⭐⭐): [上記の]プログラムを[拡張]し、
Animalにvoid speak()という仮想関数([後ほど学習する])を[追加]し、DogとCatで[それをオーバーライド]するようにしてください。 -
上級(難易度 ⭐⭐⭐): [[図書館管理システム]の]クラス[階層構造]を設計する:
Person([氏名]、[年齢])Student継承Person([学籍番号]、[貸出冊数])Teacher継承Person([社員番号]、[貸出数])- [貸出・返却機能の実装]。
- 継承:派生クラスは基底クラスのすべてのメンバを継承する
- public/protected/private 継承[アクセス権の制御]
- 派生クラスのコンストラクタ[呼び出し]基底クラスのコンストラクタ
- is-a [関係]:派生クラスは基底クラスの一種である
- [菱形]継承[虚数が必要]継承[二義性の解消]
6. 🚀 次は
[継承の]基礎を[学びました]。[次は] ポリモーフィズム([第]32[課])を[学びます]―― [これにより]基底クラスのポインタが[派生クラスの]関数を[呼び出せるようになり]、「[1つの]インターフェース、[複数の実装]」を[実現]します!



