1 of 24

C++講座

2 of 24

もくじ

  • 第1章『基本』� 第一の壁:配列と繰り返し�
  • 第2章『クラス』� 第二の壁:ポインタ�
  • 第3章『継承』� 第三の壁:ポリモーフィズム

3 of 24

第3章『継承』

第三の壁�ポリモーフィズム

4 of 24

継承

class Eigorian{

public:

int hp;

}

class Pinkri

: public Eigorian{

public:

int mp;

}

class Koshiteru

: public Eigorian{

public:

int sp;

}

えいごリアンクラスを継承した�ぴんくりクラスと�こしてるクラスを作る

: public (クラス名)

を付けると、そのクラスを

継承するという意味になる�(publicの意味は割愛)

継承元になるクラスを

「親クラス」という

継承してできたクラスを

「子クラス」という

5 of 24

継承

継承すると、

親クラスのデータを

そのまま受け継ぐ

ことができる

         class Eigorian{

         public:

          int hp;

         }

class Pinkri : public Eigorian{

public:

int mp;

}

class Koshiteru : public Eigorian{

public:

int sp;

}

えいごリアン:HPだけ

ぴんくり:HPとMP

こしてる:HPとSP

6 of 24

関数のオーバーライド

親の関数を子が持つと、子の関数が優先される

class Eigorian{

public:

int hp;

void Magic();

}

class Pinkri : public Eigorian{

public:

int mp;

void Magic();

}

Pinkri型の変数でMagicを呼ぶと

EigorianではなくPinkriのMagicが

呼ばれる(上書きされる)

7 of 24

関数のオーバーライド

関数のオーバーライドの実装

void Eigorian::Magic(){

cout << “えいごリアンの魔法” << endl;

}

void Pinkri::Magic(){

cout << “ぴんくりの魔法” << endl;

}

Pinkri::Magicで

Eigorian::Magicも

呼ぶようにするには

どうしたらいいか?

親の処理の後に

子の処理を続ける

ようにする

8 of 24

関数のオーバーライド

関数のオーバーライドの実装

void Eigorian::Magic(){

cout << “えいごリアンの魔法” << endl;

}

void Pinkri::Magic(){

Eigorian::Magic();

cout << “ぴんくりの魔法” << endl;

}

Eigorian::Magicを

呼べばいい

9 of 24

コンストラクタのオーバーライド

子クラスを作るとき、コンストラクタで

親クラスのコンストラクタを呼ぶことができる

class Eigorian{

public:

int hp;

Eigorian(int h);

}

class Pinkri : public Eigorian{

public:

int mp;

Pinkri(int h, int m);

}

10 of 24

コンストラクタのオーバーライド

コンストラクタの実装部分で

呼びたい親クラスのコンストラクタを記述する

void Eigorian::Eigorian(int h){

hp = h;

}

void Pinkri::Pinkri(int h, int m) : Eigorian(h){

mp = m;

}

Eigorianのコンストラクタ

でHPだけ設定して

もらいたいので、

HPの値(h)だけを

与えてコンストラクタを

実行する

11 of 24

デストラクタのオーバーライド

親クラスのデストラクタには必ずvirtualを付ける

消去時に自動で親クラスのデストラクタが呼ばれる

(コンストラクタのような親クラスの指定は不要)

class Eigorian{

public:

int hp;

Eigorian(int h);

virtual ~Eigorian();

}

class Pinkri : public Eigorian{

public:

int mp;

Pinkri(int h, int m);

~Pinkri();

}

12 of 24

コンストラクタとデストラクタ

コンストラクタの処理順

親クラス

子クラス

孫クラス

デストラクタの処理順

孫クラス

子クラス

親クラス

13 of 24

仮想関数

親クラスや子クラスのオブジェクトはそれぞれ

継承関係にあっても特に考えなくても使える

int main(){

Eigorian eigo(100); // HP100のえいごリアン生成

Pinkri pin(100, 50); // HP100、MP50のぴんくり生成

}

int main(){

Eigorian *eigo = new Eigorian(100);

Pinkri *pin = new Pinkri(100, 50);

delete eigo;

delete pin;

}

14 of 24

仮想関数

親クラスのポインタ型で

子クラスのオブジェクトを作ると?

int main(){

Eigorian *p = new Pinkri(100, 50);

p->Magic();

delete p;

}

このMagicは

EigorianのMagicが

呼ばれてしまう

15 of 24

仮想関数

親クラスの関数にvirtualを付けると、その関数は

仮想関数になる(継承先で処理が変わる関数)

class Eigorian{

public:

int hp;

virtual void Magic();

}

class Pinkri : public Eigorian{

public:

int mp;

void Magic();

}

virtual を関数宣言の

頭に付ける

(実装側には付けない)

16 of 24

仮想関数

EigorianのMagicがvirtualだと、

この場合はちゃんとPinkriのMagicが呼ばれる

int main(){

Eigorian *p = new Pinkri(100, 50);

p->Magic();

delete p;

}

これはPinkriのMagic

オーバーライドする元の

関数は常に頭にvirtualを

付けるのがよい

17 of 24

抽象クラス

仮想関数の中身をあえて設定せず、

継承した子クラスの方で実装してもらうようにするには

更に関数宣言の後ろに=0を付ける(純粋仮想関数)

関数の中身は空っぽだという意味である

class Eigorian{

public:

int hp;

virtual void Magic() = 0; // Eigorian::Magicは実装不要

}

純粋仮想関数が一つでもあるクラスは

「抽象クラス」といって、オブジェクトを

作れなくなる(継承前提の親クラスとなる)

18 of 24

抽象クラス

int main(){

Eigorian eigo; // エラーになる(Eigorianは抽象クラス)

Eigorian *p = new Eigorian(100); // これもエラー

}

int main(){

Eigorian *p = new Pinkri(100, 50); // これはOK�(作ってるオブジェクトはEigorianじゃなくてPinkriだから)

delete p;

}

19 of 24

ポリモーフィズム

抽象クラスはそれ単体では役に立たないが、

継承した子クラスによって行いたい処理を変えたい

場合はとても便利である

ポリモーフィズムという

Charaクラス

(抽象クラス)

Speak()が純粋仮想関数

それぞれ継承

Pinkriクラス

Baysukeクラス

Knyackiクラス

Pinkri::Speak()

「ぴんくりに気をつけてください」

Baysuke::Speak()

「オイラベイ助だよ!!」

Knyacki::Speak()

「ニャッ嫌いなのか?」

20 of 24

ポリモーフィズム

各クラスの宣言

class Chara{

public:

virtual void Speak() = 0; // 話す純粋関数

};

class Pinkri : public Chara{

public:

void Speak(); // ぴんくり会話

};

class Baysuke : public Chara{

public:

void Speak(); // ベイ助会話

};

class Knyacki : public Chara{

public:

void Speak(); // ニャッキ会話

};

21 of 24

ポリモーフィズム

各クラスの定義

void Pinkri::Speak(){

cout << “ぴんくりに気をつけてください” << endl;

}

void Baysuke::Speak(){

cout << “オイラベイ助だよ!!” << endl;

}

void Knaycki::Speak(){

cout << “ニャッ嫌いなのか?” << endl;

}

22 of 24

ポリモーフィズム

各オブジェクトを生成してしゃべらせる

int main(){

Chara *pin = new Pinkri;

Chara *bay = new Baysuke;

Chara *knya = new Knaycki;

pin->Speak();

bay->Speak();

knya->Speak();

delete pin;

delete bay;

delete knya;

}

Pinkri::Speak()

「ぴんくりに気をつけてください」

Baysuke::Speak()

「オイラベイ助だよ!!」

Knyacki::Speak()

「ニャッ嫌いなのか?」

23 of 24

ポリモーフィズム

配列を用いた同じ処理の別表現

int main(){

Chara *chara[3];

chara[0] = new Pinkri;

chara[1] = new Baysuke;

chara[2] = new Knyacki;

for (int i = 0; i < 3; i++){

chara[i]->Speak();

}

for (int i = 0; i < 3; i++){

delete chara[i];

}

}

Speak()の部分はこれ一行

だが、オブジェクトに応じて

しゃべる内容を自動で

変えてくれる

24 of 24