English 中文(简体)
Wrapping a Lua object for use in C++ with SWIG
原标题:

Currently I know how to have C++ objects instantiated and passed around in Lua using SWIG bindings, what I need is the reverse.

I am using Lua & C++ & SWIG.

I have interfaces in C++ and objects in lua, that implement methods which do the same job and have the same structure. I would like to be able to instantiate these objects in lua yet pass them around in C++ using pointers to that interface which they resemble.

As such I can imagine creating a c++ implementation of the interface which would act as a handler for said lua object, yet I don t know how to do this. The class would act as the lua objects representative or proxy in the C++ world.

To clarify I shall start with the following example code used in an answer to a similar question I asked:

C++ code:

// Represents a generic bank account
class Account {
    virtual void deposit(double amount) = 0;
};

Lua code:

SavingsAccount = { balance = 0 }
SavingsAccount.deposit = function(amount)
    SavingsAccount.balance = SavingsAccount.balance + amount
end

-- Usage
a = SavingsAccount
a.balance = 100
a.deposit(1000)

Now say that I have a class in C++ called Bank:

class Bank {
    void AddAccount(Account* a);
};

What I would like here is a mechanism for doing the following in lua:

SavingsAccount = { balance = 0 }
SavingsAccount.deposit = function(amount)
    SavingsAccount.balance = SavingsAccount.balance + amount
end

-- Usage
a = SavingsAccount
bank:AddAccount(a)

If I need to take an extra step such as instantiating a C++ class to act as a proxy and pass it the lua table with all my lua functions etc, I can imagine it looking like this:

C++ code:

// Represents a generic bank account
class ProxyAccount : public Account {
    virtual void deposit(double amount);
};

Lua code:

SavingsAccount = { balance = 0 }
SavingsAccount.deposit = function(amount)
    SavingsAccount.balance = SavingsAccount.balance + amount
end

-- Usage
a = SavingsAccount
a.balance = 100
a.deposit(1000)

proxy = program.ProxyAccount()
proxy.settable(a)
bank:AddAccount(p)

The problem here being I have no idea how I would implement the ProxyAccount class, or even what the function signature of settable would look like...

最佳回答

What I seem to gather from your examples and the discussions is that you are expecting Lua to be the primary language, and C++ to be the client. The problem is, that the Lua C interface is not designed to work like that, Lua is meant to be the client, and all the hard work is meant to be written in C so that Lua can call it effortlessly.

Now, the important question is: why don t you want to have a C representation of the object, and prefer to have it in Lua? Since C++ is a much lower level language, and object definitions must be static, and Lua dynamically defines its "objects" it is much easier to have Lua adapt to C++ objects.

Another issue I see is that you seem to be designing your Lua code in a very Object Oriented manner. Remember that even though Lua can fake Object Oriented concepts, it is not built as an Object Oriented language, and should not be used primarily as one. If you want a fully OO scripting language, use python instead.

Now if you Really want to do it the other way, and considered that the other alternatives do not work for you, then what I would recommend, is that you keep the Lua object as a coroutine, this will allow you to:

  • Keep a representation of the object in C++ (the lua_State *)
  • Have multiple individual instances of the same "object type"
  • Lua takes care of the cleanup

However, the downsides are:

  • All functions that act on an "object" need to do so through the lua API
  • There is no easy/fast way to recognize different lua types (you could use a metatable)
  • Implementation is quite cumbersome, and hard to decypher.

EDIT: Here is how you could expose the interface to an object in a script, Each object instance would be running a new lua_State, and run its script individually, thus allowing for your "Object member data" to just be globals inside the script instance. Implementing the API for the object s methods would go like this:

int move(lua_State * L)
{
  int idx = lua_getglobal(L, "this");
  assert(!lua_isnull(-1));
  AIObject * obj = static_cast<AIObject *>(lua_touserdata(L, -1));
  lua_pop(1);
  //Pop the other parameters
  obj->move(/*params*/);
}
问题回答

I m not familiar with SWIG (I know what it is but have never used it) so this may not be the answer you are looking for.

I ve been working on a C++ project and have had success using luabind. It allows you to subclass C++ objects with Lua objects. You might want to give it a try and see if it works for you.

You can bind any C function you want to Lua and call it from there. You can define in this function what you expect the contract is between your script and your C++ code. For example, the following would kind of do what you want. You ll need to add meta table information to your Lua tables so you can distinguish different Lua object types.

int lua_AddBankAccount(lua_State* L, int pos)
{
    // Assume you ve created metadata for your Lua objects.
    if (IsAccount(L, pos))
    {
       // process your  Account  Lua instance.
    }
    else
    {
       // error - tried to add a non-Account.
    }
}

You can take this further with SWIG to bind any arbitrary C method, but it s basically the same.





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签