多態性と虚関数の初歩的な理解
1、多態性
(1)「多態性」(porlymorphism)の概念について,ここでいくつかの重要な点を記す.
マルチステート性はオブジェクト向けプログラム設計における重要な特徴であり,C++ではマルチステート性をサポートし,マルチステート性を利用して拡張しやすいシステムを実現できる.
C++の多態性とは、異なる機能を持つ関数が同じ関数名で使用され、同じ関数名で異なる内容の関数を呼び出すことができることを意味します.
オブジェクト向けプログラミングにおけるマルチステートとは、関数呼び出しなどの同じメッセージを異なるオブジェクト(たとえばクラスオブジェクト)に送信し、異なるオブジェクトがメッセージを受信するときに異なる動作を生成することができることを意味する.
C++における多態性は静的多態性と動的多態性の2つに分けられる
静的多態性(コンパイル時の多態性とも呼ばれる):プログラムコンパイル時にシステムはどの関数を呼び出すかを決定し、関数のリロードによって実現することができる.eg.関数とオペレータのリロード.
動的多様性(実行時の多様性とも呼ばれる):プログラムの実行中に操作が対象となるオブジェクトを動的に決定することができ、虚関数(virtual function)によって実現される.
2、「静的多態性」に関する簡単な小例(演算子のリロード)
3、動的多態性(virtual functionで実現)
(1)同じクラスで2つの名前が同じ、パラメータ数が同じ、パラメータタイプが同じ関数を定義することはできません(これは「繰り返し定義」に属します).ただし、クラス継承階層では可能です.
たとえば、上記の例のcircleクラスとcylinderクラスではfloat area()const関数が定義されていますが、2つの関数の機能は異なります.これは合法的で、「同名上書き」の法則に従って呼び出されます.
(1)「多態性」(porlymorphism)の概念について,ここでいくつかの重要な点を記す.
マルチステート性はオブジェクト向けプログラム設計における重要な特徴であり,C++ではマルチステート性をサポートし,マルチステート性を利用して拡張しやすいシステムを実現できる.
C++の多態性とは、異なる機能を持つ関数が同じ関数名で使用され、同じ関数名で異なる内容の関数を呼び出すことができることを意味します.
オブジェクト向けプログラミングにおけるマルチステートとは、関数呼び出しなどの同じメッセージを異なるオブジェクト(たとえばクラスオブジェクト)に送信し、異なるオブジェクトがメッセージを受信するときに異なる動作を生成することができることを意味する.
C++における多態性は静的多態性と動的多態性の2つに分けられる
静的多態性(コンパイル時の多態性とも呼ばれる):プログラムコンパイル時にシステムはどの関数を呼び出すかを決定し、関数のリロードによって実現することができる.eg.関数とオペレータのリロード.
動的多様性(実行時の多様性とも呼ばれる):プログラムの実行中に操作が対象となるオブジェクトを動的に決定することができ、虚関数(virtual function)によって実現される.
2、「静的多態性」に関する簡単な小例(演算子のリロード)
#include
using namespace std;
// point
class point
{
public:
point(float a=0,float b=0);
void setpoint(float a,float b);
float getx() const
{
return x;
}
float gety() const
{
return y;
}
friend ostream& operator<
// , ,
point &pref=cy;// pref cy point , cy !!!!!!
cout<
3、動的多態性(virtual functionで実現)
(1)同じクラスで2つの名前が同じ、パラメータ数が同じ、パラメータタイプが同じ関数を定義することはできません(これは「繰り返し定義」に属します).ただし、クラス継承階層では可能です.
たとえば、上記の例のcircleクラスとcylinderクラスではfloat area()const関数が定義されていますが、2つの関数の機能は異なります.これは合法的で、「同名上書き」の法則に従って呼び出されます.
//circle area ,
float circle::area() const
{
return 3.14159*r*r;
}
//cylinder area ,
float cylinder::area() const
{
float s=2*circle::area()+2*3.14159*getr()*h;
return s;
}
(2)虚函数的提出:为了能使用同一种调用形式,既能调用派生类,又能调用基类中的同名函数,从而提出了虚函数。在C++中,虚函数的作用是,允许在派生类和积累中定义同名的函数,并且可以通过指向基类的指针或引用来访问基类和派生类中的同名的函数。
不使用虚函数时:
类中的代码:
//circle area , float circle::area() const { return 3.14159*r*r; } //cylinder area , float cylinder::area() const { float s=2*circle::area()+2*3.14159*getr()*h; return s; }
mainプログラム:int main() { circle c(3.5,6.4,5.2); cout<area()<
area()<
出力結果は下図のようになります.
虚関数は次のように使用できます.
circleクラスのarea関数で宣言されたコードを次のように変更します.他のコードは変更されません.main関数も変更されません.virtual float area() const;//
出力結果は下図のようになります.
これはマルチステートであり、同じメッセージ(ここでは関数呼び出し:area()を指す)に対して、異なるオブジェクトに異なる応答方式(実行される関数体が異なる)があります.
(3)まとめ:
ベースクラスのメンバー関数を虚関数として宣言すると、派生クラスでその関数を再定義し、新しい機能を付与できます.また、同じクラスの異なるクラスのオブジェクトをベースクラスオブジェクトへのポインタで指すことで、同じ名前の関数を呼び出すことができます.(つまり、ダミー関数とベースクラスオブジェクトを指すポインタを組み合わせることで使用します)
4、純虚関数
ベースクラスでは、ある関数を虚関数として定義する場合があります.ベースクラス自体の必要ではなく、派生クラスの必要性を考慮して、ベースクラスに関数名を残し、具体的な機能は派生クラスが自分で追加するまで残します.この場合、ベースクラスで虚関数を純虚関数として宣言できます.たとえばpointベースクラスでareaを純粋な虚関数として宣言できますが、pointベースクラスではこの関数は必要ありません.派生クラスcircleとcylinderでこの関数が必要です.// point class point { public: point(float a=0,float b=0); void setpoint(float a,float b); float getx() const { return x; } float gety() const { return y; } virtual float area() const=0;// , , , friend ostream& operator<
//point circle class circle:public point { public: circle(float a=0,float b=0,float rr=0); void setr(float r_new); float getr() const; float area() const;// friend ostream& operator<
//circle cylinder class cylinder:public circle { public: cylinder(float a=0,float b=0,float rr=0,float hh=0); void seth(float h_new); float geth() const; float area() const;// float volume() const; friend ostream& operator<
int main() { circle c(3.5,6.4,5.2); cout<area()<
area()<