目次
概要
Luaにはクラスや継承といった仕組みはありませんが、テーブルとメタテーブルを使うことで、継承のような振る舞いを実装できます。
ポイント
子テーブルに存在しないキーを参照すると__indexを通じて親テーブルから探します。
これにより、親のメソッドを子から使えます。
- Luaにはクラスや継承はない
- __index による探索で継承風に実装できる
- 子 → 親へメソッド探索が流れる
クラスの継承のような実装のサンプル
-- 親クラス
local Color1 = {}
Color1.__index = Color1
function Color1:new(name)
local obj = setmetatable({ name = name }, self)
return obj
end
function Color1:getName()
return self.name
end
-- 子クラス(親を継承)
local Color2 = {}
setmetatable(Color2, { __index = Color1 })
Color2.__index = Color2
function Color2:getChildName()
return "child:" .. self.name
end
-- 使用例
local c = Color2:new("red")
print(c:getName()) -- red(親のメソッド)
print(c:getChildName()) -- child:red(子のメソッド)
解説
① 親クラス
local Color1 = {}
Color1.__index = Color1
クラステーブルです。
__index に自分自身を設定することで、インスタンスからメソッドを参照できるようにします。
② 子クラス(継承のポイント)
setmetatable(Color2, { __index = Color1 })
ここが継承の本体です。
Color2 に存在しないキーは、メタテーブルの __index を通じて Color1 から探されます。
③ 子クラスの __index
Color2.__index = Color2
Color2:new() で作ったインスタンスのメタテーブルが Color2 になるため、この設定が必要です。
これにより「インスタンス → Color2 → Color1」という探索チェーンが成立します。
④ メソッド探索の流れ
function Color1:new(name)
local obj = setmetatable({ name = name }, self)
return obj
end
Color2:new("red")を呼ぶとき、selfはColor2になります。
そのためobjのメタテーブルはColor2になり、子クラスにnew()を別途定義する必要はありません。
⑤ メソッド探索の流れ
c:getName1()
内部では以下の順に探索されます。
1.c.getNameを探す→ない
2.cのメタテーブル(Color2)を見る→Color2.getNameはない
3.Color2のメタテーブルの__index(=Color1)を見る
4.Color1.getNameを発見→実行
これがLuaにおける継承風の仕組みです
→Color2:new("red")したが、親のColor1.getNameを使える
⑥ メソッドのオーバーライド
-- function Color2:getChildName()
function Color2:getName()
-- return "child:" .. self.name
return "override:" .. self.name
end
local c = Color2:new("red")
print(c:getName()) -- override:red(子のメソッドが呼ばれる)
仮に、子クラスで親と同名のメソッドを定義すると、子クラスの定義が優先されます。
探索順により Color2.getName が先に見つかるため、Color1.getName は呼ばれません。
関連の記事
