なぜ虚関数を使うのですか?虚関数はいつ使いますか.
2557 ワード
C++を始めて「クラス」という章を学んだばかりの頃は、虚関数が何に使われているのか分からなかった.本で挙げた例はよくわかりません.
実行結果:親Show関数
親ポインタで子オブジェクトを指し、Show関数を虚関数として宣言しないと、派生して書き換えたShow関数ではなく、親Show関数が呼び出されます.Show関数を虚関数として宣言すると、上記のコードが実行されると出力されます:サブクラスShow関数
実行結果:サブクラスShow関数
なぜ親ポインタで子オブジェクトを指すのか、私は悩んでいます.これは虚関数として宣言する必要はありません.直接サブクラスオブジェクトを定義したり、サブクラスポインタでサブクラスオブジェクトを指したりして、Show関数を呼び出したりする必要はありません.虚関数として宣言しなくても、派生して書き換えたShow関数を呼び出すことができます.
とはいえ、実際の開発ではそうではありません.いくつかのクラスライブラリ、フレームワークを使用する場合、これらのクラスライブラリ、フレームワークは事前に書かれています.クラスライブラリのソースコードを直接変更することはできません.クラスライブラリ内のクラスを派生してメンバー関数を上書きして機能を実現するしかありませんが、これらのメンバー関数にはフレームワークによって呼び出されるものがあります.この場合,虚関数を用いるのがよい方法である.
実行結果:親Put関数
上のコードを見て、親Fatherをすでに書かれたフレームワーク、クラスライブラリの中のクラスと見なして、子クラスSonは私たちの派生したクラスです.プライベートメンバー関数Putは、共通のShow関数によって呼び出されます.派生してPut関数を書き換え、サブクラスオブジェクトによってShow関数を呼び出しますが、Show関数はPut関数を呼び出します.実行後、結果として呼び出されたのは親のPut関数で、書き換えたPut関数は呼び出されませんでした.上のコードのPut関数を虚関数として宣言してから見てみましょう.
実行結果:サブクラスPut関数
虚関数として宣言された後,書き換えたPut関数の呼び出しに成功したことが分かった.これが虚関数の超典型的な役割である.
プロセス向けのC言語では、フレームワーク、クラスライブラリのコールバックがカスタマイズされた関数を必要とする場合、フレームワークをコールバックさせる関数ポインタが渡されることが多い.
オブジェクト向けの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++では、同じ目的を達成するために、フレームワークは何もしない虚関数を用意し、私たちが派生してこの虚関数を書き直して、私たちのカスタム機能を実現します.その後、ボックスはこの虚関数を呼び出します.効果は、プロシージャ言語のコールバックに向いています.