0

重複の可能性:
C++: 仮想メソッドへのアクセス

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

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 にアクセスする) などのより良い方法はありますか?

これを解決した後、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 call_functions(unsigned int func_numb)
    {
        delete current
        Base* new = current->call_func(func_numb);
        current = new;
    }
};

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

4

3 に答える 3

1

C ++には、非常に優れたイントロスペクションが組み込まれていません。つまり、おそらくご存知のように、実行時にメンバー関数を名前でルックアップして、名前付きルックアップから呼び出すことはできません。ただし、メンバー関数ポインターのテーブルを作成することはできます。たとえば、C ++ FAQ Liteエントリの例を参照してください。メンバー関数へのポインタの配列を作成して使用するにはどうすればよいですか?。(これがすでに述べた「関数配列」と同じではないことを願っていますが、それはあなたが望むことを達成するための最良の方法のようです。)

質問があれば、なぜインデックスで関数を呼び出す必要があるのですか?仮想関数は通常、タスクの独自のパラメーターセットを使用して特定のタスクを実行するために存在します。

vtableに直接アクセスする場合は、何かが機能する可能性がありますが、それは脆弱で移植性がありません。

于 2012-12-12T15:03:50.210 に答える
0

ただの大まかなコード。

void *vptr = *(void**)this;
void *method = ((void**)vptr)[index + first_method_offset];
typedef void (*method_type)();
void *m = (method_type)method;
m();

ここで、インデックス付きメソッドがvtableの最初にない場合は、first_method_offsetが必要です。

于 2012-12-12T15:00:20.517 に答える
0

メンバー関数へのポインターを使用します。

virtual Base* call_func(Base *(Base::*pf)())
{
  return this->*pf();
}

引数を算術スカラーにする必要がある場合は、ルックアップ配列を使用します。

virtual Base* call_func(unsigned int func_number)
{
  static const Base *(Base::*(table[]))() = { &Base::f_1, &Base::f_2, &Base::f_3 };
  return this->*(table[func_number])();
}
于 2012-12-12T14:57:21.750 に答える