仮想関数テーブル版Type Erasure

C++テンプレートテクニック 7-2


仮想関数テーブルの話が出てきました。話だけは知っていたのですが、実際のこんな感じという実装を見てイメージが湧きました。

しかしdrawひとつ呼ぶのにこれだけコードが必要なのもちょっとどうなのかなぁという感じもしますね。

ココまで来ると、言語仕様としてサポートされても良いような気がします。

さて、ちゃんと理解出来てるかどうか確認するのも含めて、自分で実装してみようと思います。

本では仮想関数テーブルをエミュレートする感じで実装されていましたが、自作ってことでシンプルに関数ポインタを持つだけのやり方でやってみます。

#include <iostream>
using std::cout; using std::endl;

class CClassA {
public:
    void draw () { cout << "CClassA::draw" << endl; }
};

class CClassB {
public:
    void draw () { cout << "CClassB::draw" << endl; }
};

class Foo {
public:
    void* m_data;
    void (*m_draw)(void*);
    
    template<class T>
    struct init {
        static void draw (void* data) {
            static_cast<T*>(data)->draw();
        }
    };
    
    template<class T>
    Foo(T& obj) {
        m_data = &obj;
        m_draw = &init<T>::draw;
    }
    
    void draw () {
        m_draw(m_data);
    }
};

int main () {
    CClassA cobja;
    Foo obj = cobja;
    
    obj.draw(); // CClassAのdraw呼び出し
    
    CClassB cobjb;
    obj = cobjb;
    
    obj.draw(); // CClassBのdraw呼び出し
    
    return 0;
}
$ main
CClassA::draw
CClassB::draw

うまくいってますね。こんな書き方であってるのかちょっと不安ですが。