문명ì´ëž€ ìƒí™©ì´ ì•„ë‹ˆë¼ ì›€ì§ìž„ì´ê³ , í•구가 ì•„ë‹ˆë¼ í•í•´ì´ë‹¤. ―아놀드 í† ì¸ë¹„
[[Include(분류/lua)]]
루아ì—서 í´ëž˜ìФ ì •ì˜í•˜ê¸° #
luabind는 루아ìƒì—서 다ìŒê³¼ ê°™ì€ ê°ì²´ì§€í–¥ êµ¬ë¬¸ì„ ì œê³µí•©ë‹ˆë‹¤.
class 'lua_testclass'
function lua_testclass:__init(name)
self.name = name
end
function lua_testclass:print()
print(self.name)
end
a = lua_testclass('example')
a:print()
루아 í´ëž˜ìФ ê°„ì— ìƒì†ì„ 사용하는 ê²ƒë„ ê°€ëŠ¥í•©ë‹ˆë‹¤:
class 'derived' (lua_testclass)
function derived:__init() super('derived name')
end
function derived:print()
print('Derived:print() -> ')
lua_testclass.print(self)
end
여기서 부모 í´ëž˜ìŠ¤ë¥¼ 초기화 하기위해 ìƒì„±ìžì•ˆì— super 키워드를 사용하였습니다. 사용ìžëŠ” ìƒì„±ìžì•ˆì—서 ì œì¼ë¨¼ì € super 키워드를 호출하여야만 합니다.
ì´ ì˜ˆì œë¥¼ ë³´ë©´ 알수 ìžˆë“¯ì´ ë¶€ëª¨ í´ëž˜ìŠ¤ì˜ ë§´ë²„ 함수를 í˜¸ì¶œí• ìˆ˜ 있습니다. 부모 í´ëž˜ìŠ¤ì˜ ëª¨ë“ ë§´ë²„ 함수를 알 수 있지만, 첫번째 매개변수로 self를 넣어주어야만 합니다.
루아ì—서 ìƒì† 구현 #
ë˜í•œ C++ í´ëž˜ìŠ¤ë¡œë¶€í„° 루아í´ëž˜ìŠ¤ë¥¼ ìƒì†í•˜ëŠ” 것과 루아함수로 ê°€ìƒí•¨ìˆ˜ë¥¼ 오버ë¼ì´ë”© 하는 것 ë˜í•œ 가능합니다. ì´ë ‡ê²Œ í•˜ë ¤ë©´ C++ 부모 í´ëž˜ìŠ¤ì— ëŒ€í•œ wrapper í´ëž˜ìŠ¤ë¥¼ 만들어야만 합니다. ì´ í´ëž˜ìŠ¤ëŠ” 루아í´ëž˜ìŠ¤ë¥¼ ì¸ìŠ¤í„´ìŠ¤í™” í• ë•Œ 루아 ê°ì²´ë¥¼ ë‹´ê³ ìžˆê²Œ ë í´ëž˜ìŠ¤ë¥¼ ë§í•©ë‹ˆë‹¤.
wrapper í´ëž˜ìŠ¤ëŠ” í•˜ë‚˜ì˜ ì¶”ê°€ 매개변수(luabind::object)를 ë§ë¶™ì´ëŠ” ê²ƒì„ ì œì™¸í•˜ê³ ëŠ”, 부모 í´ëž˜ìŠ¤ì™€ ë™ì¼í•œ í˜•íƒœì˜ ìƒì„±ìžë¥¼ ì œê³µí•´ì•¼ë§Œ 합니다. This is the reference to the lua object that should be held by the wrapper, and should be stored in a member variable as done in the sample below.
class base class
{
public:
baseclass(const char* s) { std::cout << s << "\n"; }
virtual void f(int a) { std::cout << "f(" << a << ")\n"; }
};
struct baseclass_wrapper: baseclass
{
luabind::object m_l;
baseclass_wrapper(luabind::object l, const char* s): baseclass(s), m_l(l) {}
virtual void f(int a) { call_member<void>(m_l, "f", a); }
static void f_static(baseclass* ptr, int a)
{
return ptr->baseclass::f(a);
}
};
module(L)
[
class_<baseclass, baseclass_wrapper>("baseclass")
.def(constructor<const char*>())
.def("f", &baseclass_wrapper::f_static)
];
Note that if you have both base classes and a base class wrapper, you must give both bases and the base class wrapper type as template parameter to class_. The order in which you specify them is not important.
If we didn't have a class wrapper, it would not be possible to pass a lua class back to C++. Since the entry points of the virtual functions would still point to the C++ base class, and not to the functions defined in lua. That's why we need one function that calls the base class' real function (used if the lua class doesn't redefine it) and one virtual function that dispatches the call into luabind, to allow it to select if a lua function should be called, or if the original function should be called. If you don't intend to derive from a C++ class, or if it doesn't have any virtual member functions, you can register it without a class wrapper.
You don't need to have a class wrapper in order to derive from a class, but if it has virtual functions you may have silent errors. The rule of thumb is: If your class has virtual functions, create a wrapper type, if it doesn't don't create a wrapper type.
overloading operators
You can overload most operators in lua for your classes. You do this by simply declaring a member function with the same name as an operator (the name of the metamethods in lua). The operators you can overload are:
- __add
- __sub
- __mul
- __div
- __pow
- __lt
- __le
- __eq
- __call
- __unm
- __tostring
class 'my_class' function my_class:__init(v) self.val = v end function my_class:__sub(v) return my_class(self.val - v.val) end function my_class:__tostring() return self.val end
This will work well as long as you only subtracts instances of my_class with each other. But If you want to be able to subtract ordinary numbers from your class too, you have to manually check the type of both operands, including the self object.
function my_class:__sub(v) if (type(self) == 'number') then return my_class(self - v.val) elseif (type(v) == 'number') then return my_class(self.val - v) else -- assume both operands are instances of my_class return my_class(self.val - v.val) end end
The reason why __sub is used as an example is because subtraction is not commutative (the order of the operands matter). That's why luabind cannot change order of the operands to make the self reference always refer to the actual class instance.
If you have two different lua classes with an overloaded operator, the operator of the right hand side type will be called. If the other operand is a C++ class with the same operator overloaded, it will be prioritized over the lua class' operator. If none of the C++ overloads matches, the lua class' operator will be called.
finalizers
If an object needs to perform actions when it's collected we provide a __finalize function that can be overridden in lua-classes. The __finalize functions will be called on all classes in the inheritance chain, starting with the most derived type.
function lua_testclass:__finalize() -- called when the an object is collected end









![[http]](/wiki/imgs/http.png)
