3

仮想メソッド テーブルを使用して、クラス内のインデックスによって関数を呼び出そうとしています...次のコードがあるとします。

class Base
{
public:
    Base() {}
    virtual ~Base() {}

    virtual Base* call_func(unsigned int func_number)
    {
       // Some way to call f_n
    }
protected:
    virtual Base* f_1() const = 0;
    virtual Base* f_2() const = 0;
    virtual Base* f_3() const = 0;
};

関数配列、if ステートメント、および case ステートメントを使用してこれを既に実装しています...つまり、ポインターのみを使用してメソッドを呼び出す (たとえば、vtable にアクセスする) などのより良い方法はありますか?

私のひどい英語で申し訳ありません:S...そして事前に感謝します!

編集:すべての提案をありがとう!私は私の質問を拡大するつもりです:

これを解決した後、f_1、f_2、f_3 の異なる実装で派生クラス (たとえば、派生 1 と派生 2) を作成し、次のようなクラス コントロールを作成します。

class Control
{
protected:
    Base* current;

public:
    Control(Base* curr = new derived1): current(curr) {}
    virtual ~Control() 
    {
        delete current;
    }
    virtual void do_something(unsigned int func_numb)
    {
        delete current
        Base* new = current->next_state(stl);
        current = new;
    }
};
4

4 に答える 4

1

仮想関数テーブルにアクセスする移植可能な方法はありません。言語仕様では、仮想ディスパッチの実装方法が指定されていないため、プログラムがアクセスできることは言うまでもなく、テーブルが存在する必要さえありません。

あなたが言及したアプローチよりも、あなたが望むことを行うための大幅に優れた方法はありません:関数ポインターのテーブル、またはif/switch条件。

于 2012-12-12T14:13:15.740 に答える
1

switch ステートメントのいずれか:

switch (func_number)
{
    case 1:
        f_1();
        break;
    case 2:
        f_2();
        break;
    case 3:
        f_3();
        break;
}

または、関数ポインターの配列を使用します。

于 2012-12-12T13:54:25.057 に答える
1

それを解決するためのすべての可能な方法を見つけたいだけだと思います。

メンバー関数へのポインターのマップ (またはベクトル) を使用して、一度 (コンストラクターまたは静的に) 初期化することができます。それはvtableをエミュレートできます。

これらの行の間の何か:

class Base
{
public:
    Base() {
        functions.insert(std::make_pair(1,&Base::f_1));
        functions.insert(std::make_pair(2,&Base::f_2));
        functions.insert(std::make_pair(3,&Base::f_3));
        }
    virtual ~Base() {}
    virtual Base* call_func(unsigned int func_number)
    {
    return (this->*functions[func_number])();
}
protected:
    std::map<unsigned int, Base*(Base:: *)()const> functions;
virtual Base* f_1() const = 0;
virtual Base* f_2() const = 0;
virtual Base* f_3() const = 0;

};

これは、継承されたクラスでも機能するはずです(call_funcただし、非仮想にします)。はい、アイテムが実際にマップ (またはベクター) 内にあるかどうか、および ではないかどうかを確認する必要がありますnullptr

于 2012-12-12T14:56:31.157 に答える
0

注1:vtableポインターを使用するよりも、メソッドマッピングまたはswitch-caseメソッドを使用してメソッドにアクセスする方が安全です。

注2:小さなアセンブリ部分はVC ++で動作しますが、他のコンパイラでは動作しません。

仮想テーブル関数にアクセスする方法はありますが、次のようになります。

// create our object
X *obj = new X();

// access the vtable pointer
int* vptr = *(int**)obj;

// set the this pointer
__asm
{
  mov ecx, obj
}

// call the first method from the vtable
( (void (*)()) vptr[0] )();

詳細な説明については、こちらをご覧ください:http: //kaisar-haque.blogspot.nl/2008/07/c-accessing-virtual-table.html

于 2012-12-12T15:08:34.720 に答える