C++: C++ 継承

最終更新:2026-08-31

Student クラスと Teacher クラスを書くとき、どちらも nameage を持ちます。

同じコードを何度も書くのは面倒です。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 メンバー
  • コンストラクタ呼び出し順序:基底クラス → 派生クラス

📝 練習問題

  1. 初級(難易度 ⭐): Animal 基底クラスを定義し、name メンバーを持たせてください。DogCat クラスを継承。

  2. 中級(難易度 ⭐⭐): 上のプログラムを改良し、Animalvoid speak() 仮想関数を追加、DogCat でオーバーライド。

  3. 上級(難易度 ⭐⭐⭐): 図書管理システムのクラスを設計:

    • Person(名前、年齢)
    • StudentPerson を継承(学籍番号、点数)
    • TeacherPerson を継承(教員番号、学科)
    • 検索と表示機能を実装。


6. 🚀 次のステップ

継承を理解したら、次は ポリモーフィズム(レッスン32) —— 基底クラスのポインタで派生クラスの関数を呼び出し、「インターフェース、多様な実装」を実現しよう!

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%