2013年11月4日月曜日

Luaを使ってクラスっぽい物を生成してCから使う方法 修正版

2013.11.04 追記

以前の投稿が激しく誤った情報を載せていたので修正。

Luaでクラス風のオブジェクトのメンバ関数を呼ぶ際は、 lua_pushvalue 関数を用いて、オブジェクトそのものを引数としてスタックにプッシュしてやる必要がある。

今回はメンバ関数内でオブジェクトのメンバを書き換えていないため、これでも正しく動作するが、 もしメンバ関数内でメンバを書き換える場合は、オブジェクト自身を return し、 lua_replace 関数を用いて返り値を元のオブジェクトに上書きしてやる必要がある。詳細は別途記事を書く予定。
2013.11.04 昨日はそうしないとうまく動かなかった筈ですが今日やったら動きました。 lua_pushvalue でコピーしたテーブルの内容を書き換えた場合って、参照元も書き換わるのかな… よく分からんのでもし分かる人がいらっしゃったらコメントとかで教えて下さい。

main.cpp

#include <lua.hpp>
#include <stdio.h>

int main( void ) {
	lua_State* L = luaL_newstate();	// Luaステートを生成
	luaL_openlibs( L );				// 標準ライブラリを読み込み

	// スクリプトの読み込み
	if( luaL_dofile(L, "script.lua") ){
		// エラー処理
		printf( "%s\n", lua_tostring( L, lua_gettop(L) ) );
		lua_close( L );
		return 0;
	}

	// 犬を生成
	lua_getglobal( L, "Dog" );					// グローバルなテーブル"Dog"をスタックに積む
	lua_getfield( L, lua_gettop( L ), "new" );	// トップに積まれたテーブルのメンバ"new"をスタックに積む
	lua_pushstring( L, "Neko" );				// 名前はNeko。犬なのにNeko。
	lua_pcall( L, 1, 1, 0 );					// 実行。関数と引数はスタックから除去され、返り値が積まれる
	lua_remove( L, -2 );						// 返り値の下にあるDogを除去
	int idx_dog = lua_gettop( L );				// Nekoのスタック上の位置を取得

	// 猫を生成
	lua_getglobal( L, "Cat" );					// グローバルなテーブル"Cat"をスタックに積む
	lua_getfield( L, lua_gettop( L ), "new" );	// トップに積まれたテーブルのメンバ"new"をスタックに積む
	lua_pushstring( L, "Inu" );					// 名前はInu。猫なのにInu。
	lua_pcall( L, 1, 1, 0 );					// 実行。関数と引数はスタックから除去され、返り値が積まれる
	lua_remove( L, -2 );						// 返り値の下にあるCatを除去
	int idx_cat = lua_gettop( L );				// Inuのスタック上の位置を取得
	
	printf( "%d object\n", lua_gettop( L ) );	// スタックのサイズが正しい事を確認

	// メンバ関数showを呼び出し
	lua_getfield( L, idx_dog, "show" );	// 関数をスタック
	printf( "%d object and function\n", lua_gettop( L ) );
	lua_pushvalue( L, idx_dog );		// 引数selfをスタック
	printf( "%d object, function, and argument\n", lua_gettop( L ) );

	// 実行
	if( lua_pcall( L, 1, 0, 0 ) ){
		// エラー出力
		printf( "%s\n", lua_tostring( L, lua_gettop( L ) ) );
	}
	
	printf( "%d objects\n", lua_gettop( L ) );
	
	// メンバ関数showを呼び出し
	lua_getfield( L, idx_cat, "show" );	// 関数をスタック
	printf( "%d object and function\n", lua_gettop( L ) );
	lua_pushvalue( L, idx_cat );		// 引数selfをスタック
	printf( "%d object, function, and argument\n", lua_gettop( L ) );

	// 実行
	if( lua_pcall( L, 1, 0, 0 ) ){
		// エラー出力
		printf( "%s\n", lua_tostring( L, lua_gettop( L ) ) );
	}
	
	printf( "%d object\n", lua_gettop( L ) );

    lua_close( L );	// 終了
    return 0;
}

script.lua

-- Dog
Dog = {}
Dog.new = function( name )
	local obj = {}
	obj.name = name
	obj.show = function( self )
		s = string.format( "%s the DOG.", self.name )
		print( s )
	end
	return obj
end

-- Cat
Cat = {}
Cat.new = function( name )
	local obj = {}
	obj.name = name
	obj.show = function( self )
		s = string.format( "%s the CAT.", self.name )
		print( s )
	end
	return obj
end

0 件のコメント: