仮想関数を定義してオーバーライド可能にする - C++ プログラミング

PROGRAM


C++ で仮想関数を定義してオーバーライド可能にする

C++ のクラスに定義したメソッドは、既定では「仮想関数」にはなりません。

仮想関数というのは、クラスを派生した時に、派生先のクラスで元のクラスのメソッドの機能を差し替えることができるメソッドです。

つまり仮想関数として定義しておいたメソッドだけが、派生先でオーバーライドすることができます。

 

ちなみに仮想関数にしなかったメソッドは、同じメソッドが派生先で実装されるとそれで隠ぺいされます。

オーバーライドはされないので、派生元自身がそのメソッドを実行したり、派生元の型のポインタ変数に派生したクラスを代入したりしたときには、派生元の方のメソッドが実行されるので注意です。

 

仮想関数を定義する

そのメソッドが仮想関数であることを示すには、プロトタイプでのメソッド定義で "virtual" キーワードを指定します。

virtual const char* toString();

このようにすることで、このメソッドは派生先で自由にオーバーライドすることができるようになります。

 

デストラクタについても同様です。

virtual ~CMyClass();

とくにデストラクタは、派生クラスを作成した場合には必ず使うものなので、基本的には virtual を付けて定義します。

 

ただし、クラスのどこかで virtual キーワードが指定されていると、そのクラスには暗黙的に vtable という仮想関数を管理するための情報が生成されて、インスタンスひとつひとつにそのアドレスが保持されるそうです。

そのため、そのクラスが派生されないことが確実な場合には、デストラクタにも virtual を付けないでおく方がメモリ効率が良くなるとのお話もありました。

派生クラスがあるかどうかはコンパイラでも判断できそうなところなので、実際に不必要な vtable がインスタンスにつけられるかどうかは判らないような気もします。

 

純粋仮想関数

C++ にはもうひとつ「純粋仮想関数」というものがあります。

これは、そのメソッドを定義した段階では実装を書かずに、実装は派生先のクラスに委ねられるメソッドです。実装がないので当然、純粋仮想関数を持ったクラスをインスタンス化することはできません。

 

定義の仕方は簡単で、プロトタイプ宣言で virtual キーワードでメソッドを宣言するのと合わせて "= 0" を末尾に記載します。

virtual const char* toString() = 0;

このようにすることで、このメソッドはこのクラスでは実装できなくなりますが、インスタンス化したいクラスでは必ずこのメソッドが実装されている必要があります。

 

ちなみにこのように、インスタンス化できないクラスのことを「抽象クラス」と呼びます。

C++ にはインターフェイスという概念がないので、代わりにこの抽象クラスを使うことでインターフェイスを統一することができます。

C++ の場合は複数のクラスを継承する「多重継承」も行えるので、純粋仮想関数だけで作ったクラスを多重継承してあげれば、インターフェイスにだいぶ近い使い方ができると思います。


[ もどる ]