仮想関数 - (2012/12/19 (水) 01:03:48) の編集履歴(バックアップ)
純粋仮想関数
仮想関数
前章で virtual キーワードをつけた関数は 仮想関数 として扱われ
オーバーライドで書き換えることができると学びました。
オーバーライドで書き換えることができると学びました。
virtual をつけずにオーバーライドした場合、オブジェクトを扱う「型」の定義に従い、
virtual をつけてオーバーライドした場合は、基底クラスの「型」として扱っても、オーバーライドされた定義が呼び出されます。
virtual をつけてオーバーライドした場合は、基底クラスの「型」として扱っても、オーバーライドされた定義が呼び出されます。
Personの自己紹介はオーバーライドされた場合派生クラスの自己紹介を優先するようになっていました。
また、オーバーライドしなくてもPersonでの定義を呼び出すことが可能です。
また、オーバーライドしなくてもPersonでの定義を呼び出すことが可能です。
純粋仮想関数
仮想関数は何かしらの定義を持ちましたが、
定義を持たない仮想関数を作ることもできます。
これを純粋仮想関数と呼び、以下のように = 0 をつけることで実現します。
定義を持たない仮想関数を作ることもできます。
これを純粋仮想関数と呼び、以下のように = 0 をつけることで実現します。
virtual 戻り値型 関数名(引数) = 0;
この純粋仮想関数のみで構成されたクラスを、抽象クラスまたはインターフェースクラスと呼びます。
インターフェースクラスは関数の定義を持っていないため、オブジェクトを作ることができません。
必ず継承し、関数を再定義して使うのです。
インターフェースクラスは関数の定義を持っていないため、オブジェクトを作ることができません。
必ず継承し、関数を再定義して使うのです。
機能の宣言のみを持ったインターフェースですが、どのようなメリットがあるかつかみにくいと思います。
多態性の章において、基底クラスのポインタには、その派生クラスであればどんなオブジェクトでも扱うことができると書きました。
インターフェースはクラス階層の土台に位置し、抽象的な宣言のみ行います。
クラス使用者はインターフェースのみ知っていれば機能を使うことができる上
インターフェースから派生した様々なオブジェクトを同じコードで処理することができます。
多態性の章において、基底クラスのポインタには、その派生クラスであればどんなオブジェクトでも扱うことができると書きました。
インターフェースはクラス階層の土台に位置し、抽象的な宣言のみ行います。
クラス使用者はインターフェースのみ知っていれば機能を使うことができる上
インターフェースから派生した様々なオブジェクトを同じコードで処理することができます。
例
図形の面積を求めるサンプルです。
抽象クラスShapeを用意し
そこから派生したRectクラス、Circleクラスでそれぞれ面積の計算方法を定義します。
抽象クラスShapeを用意し
そこから派生したRectクラス、Circleクラスでそれぞれ面積の計算方法を定義します。
Shape.h
#pragma once class Shape{ public: virtual double getArea() = 0; };
Rect.h
#pragma once #include "shape.h" class Rect : public Shape { private: double width; double height; public: Rect(double width, double height); double getArea(); };
Rect.cpp
#include "Rect.h" Rect::Rect(double width, double height){ this->width = width; this->height = height; } double Rect::getArea(){ return this->height * this->width; }
Circle.h
#pragma once #include "shape.h" class Circle : public Shape { private: double radius; public: Circle(double radius); double getArea(); };
Circle.cpp
#include "Circle.h" #define _USE_MATH_DEFINES #include < cmath > Circle::Circle(double radius) { this->radius = radius; } double Circle::getArea(){ return this->radius * this->radius * M_PI; }
main.cpp
#include < iostream > #include "Rect.h" #include "Circle.h" using namespace std; int main(void) { Shape* s; //s = new Rect(20, 30); //s = new Circle(10); cout << "図形の面積は " << s->getArea() << endl; return 0; }
問題
問題1
①「社員」クラスを作り、「働く」という純粋仮想関数を宣言せよ。
②「社員」クラスを継承し「社長」「部長」「営業」クラスを作り、それぞれ中身の異なる「働く」を定義せよ。
③main関数において、「社長」「部長」「営業」のオブジェクトをそれぞれ作れ。
④「社員」配列を用意して、③で作ったオブジェクトを配列に入れよ。
⑤社員配列をforループで回し、社員全員に「働く」関数を実行させよ。
②「社員」クラスを継承し「社長」「部長」「営業」クラスを作り、それぞれ中身の異なる「働く」を定義せよ。
③main関数において、「社長」「部長」「営業」のオブジェクトをそれぞれ作れ。
④「社員」配列を用意して、③で作ったオブジェクトを配列に入れよ。
⑤社員配列をforループで回し、社員全員に「働く」関数を実行させよ。