コンテンツにスキップ

継承

クラスのメンバ (データメンバとメンバ関数) を引き継いで 新しいクラスを作成することを継承といいます。

長方形を扱う Rectangle クラスを継承して 正方形を扱う Square クラスを作るには次のようにします。

#include <iostream>

class Rectangle {
 public:
    int Area() const {
       return height_ * width_;
    }

    int height_;
    int width_;
};

class Square : public Rectangle {
 public:
    void SetSize(int size) {
        height_ = size;
        width_ = size;
    }
};

int main() {
    Square s;
    s.SetSize(10);
    std::cout << s.Area() << std::endl;
    return 0;
}

Square クラスでは Rectangle クラスの全メンバを使用できます。 メンバ関数 SetSizeRectangle クラスのデータメンバ height_width_ を参照したり、 メンバ関数の呼び出しで s.Area としたりすることができます。

継承を行った場合もメンバを持つことができるため、 Square クラスでは Rectangle クラスにはないメンバ関数 SetSize を追加することができます。

基底クラスと派生クラス

継承の元になったクラスのことを基底クラス、 継承して作ったクラスのことを派生クラスといいます。

Rectangle クラスを継承して Square クラスを作る場合、 Rectangle クラスが基底クラス、 Square クラスが派生クラスとなります。

アクセス指定子

メンバを参照できる範囲はアクセス指定子によって制限することができます。 アクセス指定子には次の3つがあります。

アクセス指定子 自クラス 継承したクラス その他
public ✅ ✅ ✅
protected ✅ ✅ ❌
private ✅ ❌ ❌

デフォルトでは private になります。

メンバに対するアクセス指定子

private にすると自クラス内でのみメンバが参照できます。

private_member.cc

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Rectangle {
 public:
    int Area() const {
        height_ * width_;  // 参照可
    }

 private:
    int height_;
    int width_;
};

class Square : public Rectangle {
 public:
    void SetSize(int size) {
        height_ = size;  // コンパイルエラーになります
        width_ = size;   // コンパイルエラーになります
    }
};

int main() {
    Rectangle r;
    r.height_ = 10;  // コンパイルエラーになります
    r.width_ = 20;   // コンパイルエラーになります

    Square s;
    s.SetSize(10);
    return 0;
}

protected にすると自クラス内に加え、継承したクラス内でも参照できるようになります。

protected_member.cc

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Rectangle {
 public:
    int Area() const {
        height_ * width_;  // 参照可
    }

 protected:
    int height_;
    int width_;
};

class Square : public Rectangle {
 public:
    void SetSize(int size) {
        height_ = size;  // 参照可
        width_ = size;   // 参照可
    }
};

int main() {
    Rectangle r;
    r.height_ = 10;  // コンパイルエラーになります
    r.width_ = 20;   // コンパイルエラーになります

    Square s;
    s.SetSize(10);
    return 0;
}

public にすると参照できる範囲の制限はなくなります。

public_member.cc

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Rectangle {
 public:
    int Area() const {
        height_ * width_;  // 参照可
    }

 public:
    int height_;
    int width_;
};

class Square : public Rectangle {
 public:
    void SetSize(int size) {
        height_ = size;  // 参照可
        width_ = size;   // 参照可
    }
};

int main() {
    Rectangle r;
    r.height_ = 10;  // 参照可
    r.width_ = 20;   // 参照可

    Square s;
    s.SetSize(10);
    return 0;
}

アクセス指定子は次のアクセス指定子が出現するまでが有効範囲となります。 また、アクセス指定子は何度でも使用できます。

class AccessSpecifier {
    void Private1();  // デフォルトは private

 public:
    void Public1();
    void Public2();

 public:  // 対象となるメンバがなくても問題なし
 private:
    void Private2();

 private:  // アクセスレベルの変化がなくても問題なし
    void Private3();
};

読みづらいコードになってしまうのを防ぐため、 アクセス指定子の使い方についてコーディング規約で指定されることもあります。

継承に対するアクセス指定子

派生クラスではアクセス指定子によって 基底クラスのメンバを参照できる範囲をさらに制限することができます。

デフォルトでは private になります。

class Base {};

class Sub1 : public Base {};  // public 継承
class Sub2 : protected Base {};  // protected 継承
class Sub3 : private Base {};  // private 継承
class Sub4 : Base {};  // private 継承 (デフォルト)

インターフェースのクラスを継承して実装を行う場合には public を使用します。

詳細は 派生クラス - cppreference.com を参照してください。