仮想関数と純粋仮想関数の主な違いは、仮想関数がvirtualキーワードを使って宣言されたベースクラス内の関数であるのに対し、純粋仮想関数は関数定義がないベースクラス内の仮想関数である点です。
ポリモーフィズムは、OOPの重要な概念です。
ポリモーフィズムは、オブジェクトが多くの形態をとることを可能にします。
ポリモーフィズムには、アーリーバインディングとレイトバインディングと呼ばれる2つのタイプがあります。
C++は、OOPをサポートするプログラミング言語です。
したがって、プログラマはC++を使ってポリモーフィズムの概念を実装することができます。
仮想関数とは
仮想関数とは、ベースクラスでvirtualキーワードを持つ関数のことです。
これは、サブクラスが同じメソッドを他の実装で持っている場合に、静的にリンクしてはいけないことをコンパイラに指示するのに役立つ。
この概念は、以下のプログラムを参照すると理解しやすいでしょう。
図1:C++プログラム
上記のプログラムでは、クラスAはdisplayというパブリックメソッドを持っています。
クラスBはクラスAを継承しており、displayというメソッドを持っています。
どちらのメソッドも同じ名前ですが、実装が異なります。
mainメソッドでは、aをポインタ、bをB型のオブジェクトとし、aにbのアドレスを代入しています。
bのアドレスをaに代入しても(b = &a)、クラスAのdisplayメソッドが出力されていることが確認できます。
つまり、プログラムを実行する前に関数呼び出しが確定しているのです。
表示関数はコンパイル時に設定される。
これをアーリーバインディングとも呼ぶ。
実行時にコンパイラにオブジェクトの型を識別させ、関数呼び出しをバインドするために、プログラマはベースクラスで “virtual “というキーワードを使用することができる。
そのためには、上記のプログラムを少し修正すればよい。
それは、以下のように、ベースクラス関数の前にvirtualキーワードを追加することである。
図2: virtual関数を使ったC++プログラム
これで、クラスAの表示関数は仮想関数になった。
つまり、オブジェクトに応じて関数が呼び出されるのです。
したがって、これはダイナミックバインディングまたはレイトバインディングです。
純粋仮想関数とは
仮想関数はタスクを実行するものではありません。
定義や実装を持たない関数は、何もしない関数です。
したがって、このような関数は純粋仮想関数となります。
さらに、純粋仮想関数を持つクラスのオブジェクトを宣言することはできません。
このようなクラスは抽象基底クラスと呼ばれます。
サブクラスは、ベースクラスの仮想関数に定義を与えなければなりません。
クラスAの表示関数には関数定義の必要がないため、関数定義がない。
0 は、コンパイラがその関数に定義がないことを示します。
従って、クラス A の表示関数は純粋仮想関数と呼ばれます。
クラス A は純粋仮想関数を持つので、抽象基底クラスと呼ばれます。
仮想関数と純粋仮想関数の違い
定義
仮想関数とは、基底クラス内で宣言され、派生クラスで再定義またはオーバーライドできるメンバ関数のことで、純粋仮想関数とは基底クラス内の仮想関数で実装がないものを指します。
これが仮想関数と純粋仮想関数の大きな違いです。
機能定義
また、仮想関数と純粋仮想関数の大きな違いは、関数定義にあります。
仮想関数では、ベースクラスが関数定義を持っています。
しかし、純粋仮想関数では、ベースクラスは関数定義を持っていません。
しかし、純粋仮想関数では、ベースクラスは関数定義を持たず、関数宣言のみを持つ。
派生クラス
また、仮想関数と純粋仮想関数のもう一つの違いは、すべての派生クラスがベースクラスの仮想関数をオーバーライドする必要はないことです。
しかし、派生クラスは、ベースクラスの純粋仮想関数をオーバーライドする必要があります。
抽象クラス
さらに、仮想関数には抽象クラスという概念はありません。
純粋な仮想関数が少なくとも1つあれば、そのクラスは抽象クラスと呼ばれる。
成果
ベースクラスの仮想関数をオーバーライドしない派生クラスは、コンパイルエラーを起こしません。
しかし、ベースクラスの純粋仮想関数をオーバーライドしない派生クラスは、コンパイルエラーになります。
したがって、これも仮想関数と純粋仮想関数の違いです。
結論
C++では、仮想関数を書くことができます。
純粋仮想関数は、特別な仮想関数です。
仮想関数と純粋仮想関数の主な違いは、仮想関数が virtual キーワードを使って宣言された基底クラス内の関数であるのに対し、純粋仮想関数は関数定義がない基底クラス内の仮想関数である点です。