2013-11-20 87 views
0

我有一個C++主機,我使用tolua ++向Lua公開一些類。其中一個類有一個函數,它應該註冊一個來自lua的回調函數。所以當C++代碼需要調用一個Lua註冊函數時,它可以。該功能是一個表/類功能。我之前用字符串函數名(不是lua「類」的一部分)成功完成了這個,但我很好奇,如果我能夠以某種方式存儲Lua函數而不是函數名。從C++ Lua回調

我定義我的盧阿類,如:

MyClass = {} 

function MyClass:Create() 
    local obj = {} 

    -- copy all functions from MyClass table to this local obj and return it 
    local k,v 
    for k,v in pairs(obj) do 
     obj[k] = v 
    end 

    return obj 
end 

function MyClass:Enter() 
    self.CPlusClass = CPlusClass:Create() -- this is the C++ class creation, I defined a static function Create() 
    self.CPlusClass:RegisterCallback(15, self.Callback) -- this is where I want to pass this instances function to be called back from the C++ class 
end 

function MyClass:Callback(reader) 
    -- I want to be able to use self here as well so it needs to be the same instance 
end 

的MyClass的內幕:輸入()是我想要註冊的LUA「類」功能MyClass的::回調是能夠從C叫++目的。我如何將它傳遞給C++函數?類型是什麼,以便它會調用MyClass:C++中的Callback(),並傳入「self」,以便它是類的相同「實例」?

所以我知道'自我'指的是我創建的一個實際變量,我假設它將在全局表中由變量名構成,但是當你在lua的「類」中時,我怎麼能告訴變量名'自我「也指的是?如果我可以將它傳遞給我的C++函數並將其作爲字符串存儲,以便我可以調用getglobal來獲取特定的表,然後我也可以將表函數名作爲字符串傳遞給C++,得到這個,並稱之爲。但問題是,如何將'self'轉換爲它所指向的實際變量名稱,以便我可以在C++中調用getglobal來獲取該表格?

+0

'self'不是全局的,self是'table:function'語法糖定義的自動變量。函數表:class(args ...)... end'與'function table.class(s​​elf,args ...)... end'完全相同。類似地,對「tab:class(args ...)」的調用與「tab.class(tab,args ...)」相同(儘管tab僅評估一次)。 –

+0

我明白這一點。然而,我自己所指的是我在我的lua程序中創建的一個表格。我怎麼知道自我所指的是什麼變量名? – user441521

+0

您不能從其表「對象」中取消關聯函數,並在稍後再次對該表「對象」進行處理。你需要創建一個閉包作爲你的回調函數來做你想做的事情。 –

回答

2

如果您想保留RegisterCallback簽名和操作(而不是以某種方式增強它以理解對象方法回調),那麼您需要創建一個閉包並將其作爲回調傳遞。事情是這樣的:

function create_closure(obj, fun) 
    return function(...) 
     return obj[fun](...) 
    end 
end 

function MyClass:Enter() 
    self.CPlusClass = CPlusClass:Create() -- this is the C++ class creation, I defined a static function Create() 
    self.CPlusClass:RegisterCallback(15, create_closure(self, "Callback")) 
end 
+0

我的第二個參數RegisterCallback()實際上是一個字符串。我最初的希望是能夠得到自己所指的變量名,並將它連接爲「obj:Callback」,然後在C++函數中分解出來。如果我採用這種方法,第二個參數需要做什麼? – user441521

+0

'RegisterCallback'需要一個字符串?它假定名稱是一個可以稍後查找的全局函數? –

+0

這是一個字符串,因爲我的思維過程是能夠查找具有函數的表名,這意味着它假設它是全局的。我是唯一一個與此合作的人,所以我控制了這一點。然而,改變參數並不是什麼大問題,但我只需要知道閉包返回的是什麼,以及我的C++函數會期待什麼類型。此外,我的C++程序將傳遞一個lightuserobject的1個參數給閉包。我假設...自動處理所有參數? – user441521

3

導出CPlusClass「階級」從C++到Lua:這肯定C++類有它接受一個指向函數或YourCallbackClass實例RegisterCallback其使用虛擬方法分派給正確的對象。然後,您只需將YourCallbackClass導出到Lua中:在幕後,Lua版本將創建一個實例並將其提供給您的C++ RegisterCallback。 例如:

class CPlusClass { 
public: 
    RegisterCallback(int val, CPlusCallback* cb) { ... store cb for later... } 
}; 

class SomeObj; // type of Objects that you want to call back into 

class CPlusCallback { 
public: 
    typedef void (SomeObj::*Method)(); 
    CPlusCallback(SomeObj* obj, Method method) { callee=obj; method=method; } 
    call() { callee->*Method(); } 
private: 
    SomeObj* callee; 
    Method method; 
}; 

你CPlusCallback可能是不同的,這只是一個例子。例如,如果你只想要函數而不是方法,那麼你不需要存儲被調用者。如果你想要兩者,那麼CPlusCallback必須是一個基類,並且call()是虛擬的,派生類根據需要實現細節。適應你的情況。

然後出口CPlusCallback和someObj中到Lua,那麼你就可以在Lua做:

somObj = SomeObj:Create() 

function MyClass:Enter() 
    -- creates Lua instance of CPlusClass, with a user data for the C++ 
    -- counterpart as member 
    self.CPlusClass = CPlusClass:Create() 
    self.CPlusCallback = CPlusCallback:Create(someObj, someObj.method) 
    self.CPlusClass:RegisterCallback(15, self.CPlusCallback) 
end 

在上述假設someObj.method是導出,從C++類someObj中的方法,用正確的簽名無效(someObj中:: *法)()。

+0

感謝您的替代方法。目前我得到了發送self的方法,然後是lua類的字符串方法名稱,並從C++中調用它。非常類似於你在這裏做的。我很關心它是如何完成的細節,但我明白了。 – user441521