2012-12-12 138 views
3

我試圖使用虛擬方法表的索引 類調​​用函數...假設我們有下面的代碼: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-statement ...所以,有沒有更好的方法來調用方法 只使用指針(例如訪問vtable)或類似的東西?

對不起,我可怕的英語:S ...並提前致謝!編輯: 感謝您的所有建議!我打算擴展我的問題:

解決此問題後,我將創建具有f_1,f_2,f_3的不同實現的派生類(例如derived1和derived 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; 
    } 
}; 
+2

做你想做「call_func」是虛擬的? – Chubsdad

+0

好問題。我同意,感覺應該有一種方法來使用'func_number'來直接索引我們知道已經存在的指針表(在所有常見的實現中)。可悲的是,我認爲沒有。 「if」或「switch」是唯一的出路,因爲你需要虛擬呼叫。 –

+0

@NicholasWilson:問題在於它只存在於「所有常見實現」中,而不是所有可能的實現中。語言規範並不要求它在那裏,所以沒有可移植的方式來訪問它。 –

回答

1

要麼的switch語句:

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

或者使用函數指針陣列。

+0

對不起,當我說病例陳述我想說switch-statement – gvo

+1

@gvo:啊,我錯過了你的問題。無論如何,這可能是最好的方式。這裏有一點氣味。也許如果你給我們更高層次的解釋你想要做的事情,我們可以給你一些更好的想法。 –

1

沒有便攜的方式來訪問虛函數表;語言規範並未指定如何實現虛擬調度,因此不需要表甚至存在,更不用說程序可以訪問了。

沒有比你提到的方法做得更好的方法:一個函數指針表或者一個if/switch條件。

+0

好的:(謝謝,我認爲維基百科與他的虛擬方法表使用僞C++的文章混淆了我 – gvo

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

0

注1:使用方法映射或開關大小寫方法比使用vtable指針更安全。

注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