2011-01-21 7 views
6

私はかつてluaのクラスメソッドをオーバーライドできると思ったので、C++でその関数を呼び出すと、luaでオーバーライドされたことが行われるようになりました。私はこのように、意味:luaのC++メソッドをオーバーライドしてC++で呼び戻す

C++クラス


class Person { 
public: 
    Person(); // ctr 
    virtual void shout(); // Meant to be overriden 
}; 

はLUAで、私はオブジェクトを使用できるように、私は、そのクラスは、LUAにバインドされていると仮定します


--Lua code 
p = Person:new() 
p:shout() 

何が実現しようとしているのは次のようなものです:

ルアファイル


--luafile.lua 
p = Person:new() --instantiate 

--override shout() 
p.shout = function(self) print("OVERRIDEN!") end 

C++コード上記のコードで


int main() { 
    lua_State* l = lua_open(); 
    luaL_loadlibs(l); 
    bind_person_class(l); 

    luaL_dofile("luafile.lua"); 
    Person* p = (Person*) get_userdata_in_global(l, "p"); // get the created person in lua 
    p->shout(); // expecting "OVERRIDEN" to be printed on screen 

    lua_close(l); 
    return 0; 
} 

、あなたは私がLUAで人のメソッドをオーバーライドし、オーバーライドメソッドは、C++から呼び出されることを期待しようとしていることがわかります。しかし、私が試してみると、オーバーライドされたメソッドは実行されません。私が達成しようとしているのは、overridenメソッドがC++で実行されることです。どのようにこれを達成するのですか?

===================

私はこれを達成するための方法を考えたが、私はこれが良いかはわかりません。私の考えは、エクスポートされたクラスは、このクラスのインスタンスを保持するために使用されるluaのグローバル変数名を表す文字列を持つ必要があります。


class Person { 
public: 
    Person(); 
    string luaVarName; // lua's global variable to hold this class 
    virtual void shout() { 
    luaL_dostring(luaVarName + ":shoutScript()"); // now shout will call shoutScript() in lua 
    } 
}; 

ので、LUAでは、オブジェクトがshoutScript()を実装し、オブジェクトへのグローバルVAR割り当てること責任がある:このように上記のコードで


--LUA 
p = Person:new() 
p.shoutScript = function(self) print("OVERRIDEN") end 
p.luaVarName = "p" 

を、私は私が望むものを達成することができます(避難所しかし、それをテストしていない)。しかし、には、私が望むものを達成するための他の適切な方法がありますか?

+0

最初のパターンが失敗する理由を理解していますか? – GManNickG

+0

@GMan:私は本当にメソッドをオーバーライドしていないと思います。 AFAIK、C ​​++でメソッド(または関数)を呼び出すと、命令が配置されているアドレスを参照しています。また、関数がオーバーライドされたときに別のアドレスを参照する仕組みがあります。ですから、LUAでそれを "オーバーライド"すると、C++はそれについて知りませんので、実際の関数が呼び出されます。 CMIIW。 – Radi

答えて

3

、ルアへのQtの自動化された結合、仮想メソッドを持っている私たちが結合し、各クラスのために、我々はLuaの状態に自分自身を登録し、プロキシ「シェル」クラスを作成することです。

は、だからあなた(簡体字)クラス:

class Person { 
public: 
    virtual void shout(); // Meant to be overriden 
}; 

私たちは、以下のクラスを生成します。

class lqt_shell_Person : public Person { 
    lua_State *L; 
public: 
    lqt_shell_Person(lua_State *L); // registers itself into the Lua state 
    virtual void shout(); 
}; 

私たちは、ユーザデータを使用してLuaの中でこれらのオブジェクトを表します。それぞれには独自の環境テーブルがあり、__newindex__indexのメタメソッド(環境内ではファンクションを参照し、クラステーブルではファンクションを参照)を指定します。これを使用して、ユーザーはカスタムフィールドをオブジェクトに格納できます。私たちのlqt_shell_Person::shout方法で

p = Person.new() 
function p:shout() print("Hello world!") end 

、我々は最初の引数を取得した後、機能shoutは、ユーザデータの環境テーブルに存在するかどうかをチェックします。彼はまた、このように、仮想関数を実装することができます。存在すれば、それを引数と呼ぶ。何もない場合は、元の関数を呼び出します。抽象メソッドの場合、私たちはLuaエラーをスローします。

あなたはこれが便利だと思います。

+0

@マイケル:ありがとう。それは非常に良い解決策です:)私が探しているもの。 – Radi

2

ルアは「理想的には」C++とは異なります。ルアはprototype-based OO言語です。 C++はクラスベースのOO言語です。 Luaはオブジェクトのインタフェース実行時を変更することができ、C++はオブジェクトが構築された後にオブジェクト型を変更することはできません。

これまでのように、あなたのluaオブジェクトのインターフェイスで行う変更は、C++プログラムに反映されずにluaにとどまります。我々はlqtでやった何

+1

ありがとうございます。これは私にとって事をより明確にします。しかし、私は本当に私が説明したことを達成するための他の(よりエレガントな)方法を知りたい。あるいはもっと一般的なことを尋ねたはずです。オブジェクトレベル(C++)でLuaのバリエーションを実装する適切な方法は何ですか? – Radi

関連する問題