継承のセットアップ
CoddyのLuaジャーニー「Object Oriented Programming」セクションの一部 — レッスン 31/70。
これまで、各オブジェクトが単一のプロトタイプテーブルでメソッドを検索するクラスを作成してきました。しかし、あるクラスを別のクラスに基づいて構築したい場合はどうすればよいでしょうか?ここで継承(inheritance)の出番です。子クラスは親クラスのすべてにアクセスでき、同時に独自の機能を追加することができます。
重要な洞察は、クラスのテーブル自体がメタテーブルを持つことができるということです。Luaが子クラスの中で何かを見つけられないとき、子のメタテーブルの __index(これは親クラスを指しています)を探します。
-- 親クラス
local Animal = {}
Animal.__index = Animal
function Animal:new()
local obj = {}
setmetatable(obj, Animal)
return obj
end
function Animal:breathe()
print("Breathing...")
end継承の設定は以下の通りです。子クラスを作成し、そのメタテーブルが親を参照するように設定します:
-- 子クラス
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})この1行—setmetatable(Dog, {__index = Animal})—が継承関係を作成します。DogのインスタンスがDog内で見つからないメソッドを呼び出すと、LuaはAnimalを確認します。
ルックアップチェーンは次のように動作します:instance → Dog → Animal。各ステップでは、__index を使用して次に検索するテーブルを見つけます。これにより、子クラスは親のメソッドをコピーすることなく、すべての親メソッドを自動的に継承できます。
チャレンジ
簡単最初の継承階層を構築しましょう!Machineクラスをベースとし、そこからRobotクラスが継承する、シンプルな親子クラスの関係を作成します。
コードは3つのファイルに分けて構成します:
Machine.lua: 標準的なクラスパターンを使用して親クラスを定義します。:new()コンストラクタと、Machine is operationalと出力する:status()メソッドを含めてください。__indexの設定と、ファイルの最後でクラスを返すことを忘れないでください。Robot.lua: Machineから継承する子クラスを定義します。Machineモジュールをrequireし、独自の__indexを持つRobotテーブルをセットアップし、setmetatable(Robot, {__index = Machine})を使用して継承関係を確立します。Robotをメタテーブルとしてインスタンスを作成する:new()コンストラクタを含めてください。main.lua: Robotモジュールをrequireし、Robotのインスタンスを作成して、継承された:status()メソッドを呼び出すことで、すべてをまとめます。
ここでの重要な概念は、Robotクラス自体は:status()を定義していないということです。メタテーブルのチェーンを通じて、Machineからこのメソッドを継承します。Robotインスタンスで:status()を呼び出すと、LuaはまずRobot内を探し、見つからない場合は__indexのリンクを辿ってMachineに到達し、そこでメソッドを発見します。
出力は以下のようになるはずです:
Machine is operationalこの1行は、継承が機能していることを証明しています。Robotが親クラスでのみ定義されているメソッドへのアクセスに成功しました!
チートシート
Luaで継承を作成するには、__indexを使用してクラス・テーブルのメタテーブルが親クラスを指すように設定します:
-- 親クラス
local Animal = {}
Animal.__index = Animal
function Animal:new()
local obj = {}
setmetatable(obj, Animal)
return obj
end
function Animal:breathe()
print("Breathing...")
end
-- 子クラス
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})継承のリンクはsetmetatable(Dog, {__index = Animal})で作成されます。これにより、DogのインスタンスはAnimalのメソッドに自動的にアクセスできるようになります。
ルックアップ・チェーンは、インスタンス → 子クラス → 親クラスの順になります。各ステップで__indexを使用して、次に検索するテーブルを見つけます。
自分で試してみよう
-- main.lua: すべてを統合する
-- TODO: Robotモジュールを読み込む
-- TODO: Robot:new() を使用して Robot インスタンスを作成する
-- TODO: ロボットインスタンスで継承された :status() メソッドを呼び出す
-- これにより "Machine is operational" と表示されるはずです
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。