仮想テーブルは関数ポインタの配列です。すべての関数が異なる署名を持っているので、どうすればそれを実装できますか?
3 に答える
あなたはそれを実装しません。
コンパイラはそれ(または同等の機能を持つもの)を生成し、型システムによって制約されないため、関数アドレスを単純に保存し、それらを正しく呼び出すために必要なコードを生成できます。
struct
配列ではなく、異なるタイプの関数ポインタを含むものを使用して、漠然と似たものを実装できます。これは、C で動的ポリモーフィズムを実装する非常に一般的な方法です。たとえば、Linux カーネルは、次の行に沿ってインターフェイスを定義することにより、ファイルのようなオブジェクトにポリモーフィックな動作を提供します。
struct fileops {
int (*fo_read) (struct file *fp, ...);
int (*fo_write) (struct file *fp, ...);
// and so on
};
コンパイル時にすべての関数がわかっている場合は、異なる型の関数ポインターの構造体を使用できます (ただし、コンパイル時にすべての関数がわかっている場合は、仮想メソッドを持つクラスを使用しないでください)。
実行時にこれを行いたい場合は、void*
おそらく の配列で十分です。ポインターを格納するときにポインターをキャストし、呼び出す前に (正しい型に) 再度キャストする必要があります。もちろん、関数の型 (呼び出し規約を含む) を別の場所で追跡する必要があります。
これで何をしようとしているのかを知らなければ、より有用な答えを出すことは非常に困難です.
コードで vtables を実装する正当な理由があります。ただし、これらは実装の詳細であるため、「C++」だけでなく、既知の ABI をターゲットにする必要があります。私がこれを行ったのは、実行時に新しい COM クラスを動的に作成する実験だけでした (COM オブジェクトに期待される ABI は、最初の 3 つの関数がインターフェイスを__stdcall
実装する呼び出し規則に従う関数を含む vtable へのポインターです)。IUnknown
仮想テーブル内の関数のシグネチャが異なる場合は、異種の型を持つメンバーを含む構造型として実装する必要があります。
または、シグネチャが何であるかを示す他の情報がある場合は、関数ポインターを別の関数ポインター型にキャストできますが、呼び出す前に正しい型にキャストし直す必要があります。