なぜ虚関数を使うのですか?虚関数はいつ使いますか.

2557 ワード

C++を始めて「クラス」という章を学んだばかりの頃は、虚関数が何に使われているのか分からなかった.本で挙げた例はよくわかりません.
#include<iostream>
using namespace std;

class Father
{
public:
	void Show()
	{
		cout<<"  Show  "<<endl;
	}
};

class Son:public Father
{
public:
	void Show()
	{
		cout<<"  Show  "<<endl;
	}
};

int main()
{
	Father *p = new Son;
	p->Show();
	delete p;
}

実行結果:親Show関数
親ポインタで子オブジェクトを指し、Show関数を虚関数として宣言しないと、派生して書き換えたShow関数ではなく、親Show関数が呼び出されます.Show関数を虚関数として宣言すると、上記のコードが実行されると出力されます:サブクラスShow関数
#include<iostream>
using namespace std;

class Father
{
public:
	void Show()
	{
		cout<<"  Show  "<<endl;
	}
};

class Son:public Father
{
public:
	void Show()
	{
		cout<<"  Show  "<<endl;
	}
};

int main()
{
	Son a;
	a.Show();
}

実行結果:サブクラスShow関数
なぜ親ポインタで子オブジェクトを指すのか、私は悩んでいます.これは虚関数として宣言する必要はありません.直接サブクラスオブジェクトを定義したり、サブクラスポインタでサブクラスオブジェクトを指したりして、Show関数を呼び出したりする必要はありません.虚関数として宣言しなくても、派生して書き換えたShow関数を呼び出すことができます.
とはいえ、実際の開発ではそうではありません.いくつかのクラスライブラリ、フレームワークを使用する場合、これらのクラスライブラリ、フレームワークは事前に書かれています.クラスライブラリのソースコードを直接変更することはできません.クラスライブラリ内のクラスを派生してメンバー関数を上書きして機能を実現するしかありませんが、これらのメンバー関数にはフレームワークによって呼び出されるものがあります.この場合,虚関数を用いるのがよい方法である.
#include<iostream>
using namespace std;

class Father
{
	void Put()
	{
		cout<<"  Put  "<<endl;
	}
public:
	void Show()
	{
		Put();
	}
};

class Son:public Father
{
	void Put()
	{
		cout<<"  Put  "<<endl;
	}
};

int main()
{
	Son a;
	a.Show();
}

実行結果:親Put関数
上のコードを見て、親Fatherをすでに書かれたフレームワーク、クラスライブラリの中のクラスと見なして、子クラスSonは私たちの派生したクラスです.プライベートメンバー関数Putは、共通のShow関数によって呼び出されます.派生してPut関数を書き換え、サブクラスオブジェクトによってShow関数を呼び出しますが、Show関数はPut関数を呼び出します.実行後、結果として呼び出されたのは親のPut関数で、書き換えたPut関数は呼び出されませんでした.上のコードのPut関数を虚関数として宣言してから見てみましょう.
#include<iostream>
using namespace std;

class Father
{
	virtual void Put()
	{
		cout<<"  Put  "<<endl;
	}
public:
	void Show()
	{
		Put();
	}
};

class Son:public Father
{
	virtual void Put()
	{
		cout<<"  Put  "<<endl;
	}
};

int main()
{
	Son a;
	a.Show();
}

実行結果:サブクラスPut関数
虚関数として宣言された後,書き換えたPut関数の呼び出しに成功したことが分かった.これが虚関数の超典型的な役割である.
プロセス向けのC言語では、フレームワーク、クラスライブラリのコールバックがカスタマイズされた関数を必要とする場合、フレームワークをコールバックさせる関数ポインタが渡されることが多い.
オブジェクト向けのC++では、同じ目的を達成するために、フレームワークは何もしない虚関数を用意し、私たちが派生してこの虚関数を書き直して、私たちのカスタム機能を実現します.その後、ボックスはこの虚関数を呼び出します.効果は、プロシージャ言語のコールバックに向いています.