2013-12-03 21 views
2

我在閱讀有關委派,我想能夠在基類內調用任何函數傳遞作爲參數取決於事件,所以如果例如我有一個解析器對象,並且我想從另一個對象分配什麼方法來調用依賴找到什麼標記。我做了波紋管,它可以工作,但我不確定它是否是正確的方式,或者它是否像便攜式一樣。從C++派生類的基類中調用未定義的成員函數是否安全?

class base{ 
public: 
    typedef void (base::*methodPTR)(); 
    methodPTR pfn; 

    void setMethod(methodPTR fn) 
    { 
     pfn = fn; 
    } 
    void run(){ 
     if(pfn) (this->*pfn)(); 
    } 
}; 

class a : public base { 
public: 
}; 

class b : public base 
{ 
    a ob; 
public: 
    void init() 
    { 
      //this function fn is not define neither in object "a" or "base" 
      //but still I can assign arbitrary member function just like I wanted 
     ob.setMethod(static_cast<base::methodPTR>(&b::fn)); 
    } 

    void fn() 
    { 
     cout << "from class b!" << endl; 
    } 

    void test() 
    { 
     ob.run(); 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    b x; 
    x.init(); 
    x.test(); 

    return 0; 
} 
+1

我看到的問題是,當你通過pfn調用並輸入b :: fn()時,「this」指針將不正確。如果你試圖訪問「b」的成員,它會得到錯誤的值。我通過指針「this」指向「ob」實例來調用b :: fn()時從輸出語句中添加。這只是「這個」的副作用,並沒有真正被傳遞,並且它是從「a」類中的一個方法調用的。 –

+0

@BrianWalker THX發現這一點,我已經完全監督這一點(類'a'被用作成員),這使得我的答案無用。總之:便攜式是的,正確的方式不! –

+0

這是實現多態的一種相當常見的方式,不需要vtable的開銷。安全/便攜,是的......但你肯定會想評論你在做什麼,爲什麼(具體解釋你爲什麼需要避免使用虛表)。另外,當你調用函數時,不需要'this'。把它稱爲'(* fpn)();' –

回答

0

做你正在做的是安全的,只要你相信,你永遠不會調用對象,這不是真正的指針所來自的類型(即一個你不上成員指針在base上撥打a::x)。

+0

我認爲這是在C++中創建回調函數的一個好方法,因爲沒有辦法靈活地指定我自己的方法並且能夠使用多個回調方法。例如,在LUA中,你必須傳遞常規的C函數,但是如果它們能夠這樣做,我就可以使用C++方法,但我認爲它不適合或便攜,因爲我從來沒有見過任何人使用它。 – Jman

+0

正如你所說你不能訪問這個指針,因爲它們是不同的,所以有必要也傳遞類指針,並把它稱爲類指針,而不是這個o.class基類{public: \t typedef void(base :: * methodPTR)(); \t typedef struct callable_fun { \t \t base * base; \t \t methodPTR fn; \t}; callable_fun pfn; (methodPTR fn,base * clase) \t \t pfn。fn = fn; \t \t pfn.base = clase; (pfn.fn)((pfn.base) - > * pfn.fn)();如果(pfn.fn)(pfn.base) - > * pfn.fn)();如果(pfn.base) - > * pfn.fn) } }; – Jman

0

試試這個問題的模板解決方案,在這個例子中我確定使用正確的對象來調用正確的函數。 如果我們有地圖對象和回調,並且可能會根據某些條件調用它們,我們可以使用它。

//store objects vs callbacks 
    //you could replace int in map with some condition or key to invoke a callback 
#include <iostream> 
#include <map> 

using namespace std; 

template<class T> 
class A { 
    protected: 
    void (T::*curr_f)(); 
    private: 
    static std::map<int, std::map<T*,void (T::*)() > > callBacks; 
    public: 

    virtual void set(void (T::*f)()) { 
    curr_f = f; 
    cout<<"Set in A"<<endl; 
    T* obj = new T(); 
    static int x = 0; 
    callBacks[++x][obj] = f; 
    //  (obj->*curr_f)(); 
    } 

    virtual void new_function() {cout<<"in A"<<endl;}; 

    static void run() 
    { 
    for(typename std::map<int,std::map<T*,void (T::*)() > >::iterator itr = A<T>::callBacks.begin(); 
     itr != A<T>::callBacks.end(); ++itr) 
    { 
     for(typename std::map<T*,void (T::*)() >::iterator itr2 = itr->second.begin(); 
      itr2 != itr->second.end(); ++itr2) 
     { 
     ((itr2->first)->*(itr2->second))(); 
     } 
    } 
    } 

}; 

template<class T> 
std::map<int, std::map<T*,void (T::*)() > > A<T>::callBacks; 

class B :public A<B> { 

    public: 
    void func() { 
     set(&B::new_function); 
    }; 
    void new_function() {cout<<"in B"<<endl;}; 

}; 

class C:public A<C> { 

    public: 
    void func() { 
     set(&C::new_function); 
    }; 
    void new_function() {cout<<"in C"<<endl;}; 

}; 

int main() 
{ 

    B obj1; 
    C obj2; 
    obj1.func(); 
    obj2.func(); 
    A<B>::run(); 
    A<C>::run(); 
} 
+0

我希望能夠調用不一定會粘附的函數,我發現Delphi中的語言會發生這種情況,我可能有一些帶有按鈕實例的表單對象,當按鈕被觸發時,它會調用窗體中指定的任何函數成員。我看到很多情況下,這可能是有用的,包括我想寫一些算法需要回調的情況下,或者像一個解析器,可能有一些回調,在Lua的情況下,一個是限制使用C回調函數。 – Jman

+0

@Jman我會修改我的程序。 – Nik

相關問題