「C++言語」の「継承」の仕組みを身に付けよう!
これまで「クラス」の作り方や使い方について学んできましたが、今回はクラスに「親子関係」を作ることができる「継承」について勉強していきます。
ですが、「継承」については以前に少し学んだことがあって、難しくて理解ができなかったので、ちょっとずつ学んでいきたいと思います。
まだこの先に学ぶ内容がわからないのですが、たぶん「C++言語学習」では、ここが「山場」になるような気がしています。
「クラスの親子関係」を作る「継承」の仕組みとは?
これまで学んできたクラスはそれぞれが「独立」して存在しているため、何も関係性がありませんでした。
クラスに「親子関係」を作ることで、「プログラムの重複を減らす」ことができ、「プログラムの変更も行いやすくなる」という利点があるみたいなので、さっそく「継承」について学んでいきましょう。
今回は、「自転車(Bicycle)」を元にさまざまなクラスの作成に取り組んでみたいと思います。
他にも、「電動自転車(ElectricBicycle)」や、「マウンテンバイク(MountainBike)」クラスを作ってみたいと思います。
これらのクラスに「親子関係」を作ることで、「継承の仕組み」を作っていきます。
まず、「親(基底)」となる「Bicycle」クラスを作っていきたいと思いますが、どのような内容にするかをいろいろと考えていました。
「基底クラス」を作る
これから作るクラスの関係は、
のようになります。
「Bicycle」クラスが持っている「メンバ」と「メンバ関数」は、
- speed
- 自転車の速さ
- getSpeed()
- 「自転車の速さ」を取得するゲッター
- forward()
- 前へ進む
- brake()
- 減速する
のようにしたいと思います。
「Bicycle」クラスを作ってみると、まず、「ヘッダーファイル」は、
#ifndef ___CLASS_Bicycle #define ___CLASS_Bicycle class Bicycle { protected: int speed; // 現在の速度 public: Bicycle(); // コンストラクタ int getSpeed(); // 現在の速度を取得するゲッター void forward(int increaseSpeed); // 前へ進む void brake(); // ブレーキを掛ける }; #endif
そして、「実装ファイル」は次のようになります。
#include <iostream> #include "Bicycle.h" // コンストラクタ Bicycle::Bicycle(){ speed = 0; } // 現在の速度を取得するゲッター int Bicycle::getSpeed(){ return speed; } // 前へ進む void Bicycle::forward(int increaseSpeed){ speed += increaseSpeed; } // ブレーキを掛ける void Bicycle::brake(){ if( speed > 0){ speed -= 1; } }
もっといろいろな機能を実装できそうですが、自分の頭では把握ができなくなりそうなので、今回はかなりシンプルな構成のクラスを作りました。
このクラスは「継承される元となるクラス」なのですが、「C++言語」では「基底クラス」と呼ばれているそうです。
「派生クラス」を作る
継承される「ElectricBicycle」クラスの「ヘッダーファイル」は、
#ifndef ___CLASS_ElectricBicycle #define ___CLASS_ElectricBicycle #include "Bicycle.h" class ElectricBicycle : public Bicycle { public: void motorAssistForward(); //「モーターアシスト」を使った前進 }; #endif
のようになります。
電動自転車なので、「モーターアシストを使った前進機能」を作成してみました。
このクラスの「実装ファイル」は、
#include <iostream> #include "ElectricBicycle.h" //「モーターアシスト」を使った前進 void ElectricBicycle::motorAssistForward(){ forward(3); }
のように作ってみました。
そして、「MountainBike」クラスの「ヘッダーファイル」は、
#ifndef ___CLASS_MountainBike #define ___CLASS_MountainBike #include "ElectricBicycle.h" class MountainBike : public Bicycle { public: void gearForward(); // 変速ギアを利用して前進 }; #endif
のようになり、マウンテンバイクなので、「変速ギアを利用した前進機能」を作ってみました。
「実装ファイル」の内容は、
#include <iostream> #include "MountainBike.h" // 変速ギアを利用して前進 void MountainBike::gearForward(){ forward(5); }
のようになります。
このように「継承されるクラス」のことは「派生クラス」と呼ぶそうです。
「継承関係」の作り方
「C++言語」の継承関係には「3つ」の種類があり、
- private
- proctected
- public
の3つの継承によって、「基底クラス」のメンバの公開範囲が異なるとのことでした。
まず、クラスに「継承関係」を作るためには、
class 継承するクラス : 継承の種類 基底クラス { // メンバ }
のように「ヘッダーファイル」に書くことで、継承関係を作ることができます。
「private」の場合は、「派生クラス」から「基底クラス」の非公開のメンバにはアクセスができないとのことでした。
これはなんとなくわかるかも。
「proctected」の場合は、「基底クラス」の「public」「protected」は「派生クラス」では、「protected」として扱われるとのことでした。
「public」の場合は、「基底クラス」の「private」メンバ以外は、「派生クラス」でも「基底クラスと同様の扱い」になるとのことでした。
メンバの扱い方が継承方法で変化するところがなんか複雑ですね・・・
そもそも、「継承」を使う理由は、「基底クラス(親クラス)」の「メンバ・メンバ関数」を「派生クラス」でも使えるようにすることにあります。
これまでに作ったクラスを実行する「main」関数を作って実行してみると、
#include <iostream> #include <string> #include "ElectricBicycle.h" #include "MountainBike.h" using namespace std; int main() { // 「ElectricBicycle」クラス ElectricBicycle eb; eb.motorAssistForward(); cout << "「ElectricBicycle」のスピード=" << eb.getSpeed() << endl; // 「MountainBike」クラス MountainBike mb; mb.gearForward(); cout << "「MountainBike」のスピード=" << mb.getSpeed() << endl; return 0; }
のようになります。
このプログラムを実行すると、
「ElectricBicycle」のスピード=3 「MountainBike」のスピード=5
のように表示されます。
「motorAssistForward」関数と「gearForward」関数の中では、「基底クラス」の「Bicycle」クラスで定義されている「forward」関数を使って、「speed」の値を増やしています。
このように「派生クラス」で「基底クラス」のメンバを利用することができるのが「継承」の仕組みです。
まだなんとなくしか理解できていないところもありますが、これまでより「継承」の考え方が理解できてきたような気がします。
でも、積極的にどんどん使っていくことはまだ難しいので、さらにいろいろなクラスを作り、クラスの使い方を身に付けていきたいと思います。
→(前へ)「C言語」の「デストラクタ・インライン関数・静的メンバ」を勉強しよう!