メソッドの継承
CoddyのLuaジャーニー「Object Oriented Programming」セクションの一部 — レッスン 32/70。
継承関係が確立されると、子クラスのインスタンスは自動的にすべての親メソッドにアクセスできるようになります。これはLuaのルックアップチェーンを通じて行われます。インスタンスのメソッドを呼び出すと、Luaは目的のものが見つかるまで、接続された各テーブルを順番に検索します。
Animal が :breathe() メソッドを定義している、次のような構成を考えてみましょう:
local Animal = {}
Animal.__index = Animal
function Animal:new()
local obj = {}
setmetatable(obj, Animal)
return obj
end
function Animal:breathe()
print("Breathing...")
end
-- DogはAnimalを継承します
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new()
local obj = {}
setmetatable(obj, Dog)
return obj
endDogを作成し、親のメソッドを呼び出したときに何が起こるか見てみましょう:
local buddy = Dog:new()
buddy:breathe() -- 出力: 呼吸しています...Dogクラスは:breathe()を定義していませんが、正常に動作します。Luaはまずbuddyを確認し、何も見つからないため、次にDogを確認しますが、そこでも見つからず、最終的にAnimalの中でそれを見つけます。この自動的なメソッド継承により、共有される振る舞いを親クラスに一度書くだけで、すべての小クラスが即座にその恩恵を受けることができます。
チャレンジ
簡単メソッドの継承を実際に確認するために、シンプルな生物の階層構造を構築しましょう!Animalという親クラスとDogという子クラスを作成し、DogのインスタンスがAnimalで定義されたメソッドを使用できることを実証します。
コードは以下の3つのファイルに分けて構成します:
Animal.lua: 標準的なクラスパターンを使用して親クラスを定義します。動物の名前を保存する:new(name)コンストラクタと、動物の名前の後にmakes a soundと出力する:speak()メソッドを含めてください。ファイルの最後でクラスを返します。Dog.lua: Animalから継承する子クラスを定義します。Animalモジュールをrequireし、DogがAnimalのメソッドにアクセスできるように継承リンクを設定します。名前を保存し、Dogをメタテーブルとして設定する:new(name)コンストラクタを含めてください。Dogクラス自体には:speak()メソッドを定義しないでください。これはAnimalから継承されます。main.lua: Dogモジュールをrequireし、入力から名前を読み取り、その名前でDogのインスタンスを作成して、そのインスタンスに対して:speak()メソッドを呼び出します。
入力として、犬の名前を1つ受け取ります。
例えば、入力が Buddy の場合、出力は以下のようになります:
Buddy makes a soundここでのポイントは、Dogクラスが :speak() を定義していないにもかかわらず、Dogインスタンスでそれを呼び出すと完璧に動作することです。Luaは、DogインスタンスからDogクラス、そしてメソッドが見つかるAnimalクラスへとルックアップチェーンを辿ります。これが継承の仕組みです!
チートシート
子クラスのインスタンスは、Luaのルックアップチェーンを通じて、親クラスのすべてのメソッドに自動的にアクセスできます。インスタンスでメソッドが呼び出されると、Luaはメソッドが見つかるまで、接続された各テーブルを検索します。
継承の設定
親クラスの定義:
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})
function Dog:new()
local obj = {}
setmetatable(obj, Dog)
return obj
end継承されたメソッドの使用
子クラスのインスタンスは、子クラスで定義されていなくても親クラスのメソッドを呼び出すことができます。
local buddy = Dog:new()
buddy:breathe() -- 出力: Breathing...ルックアップチェーン: Luaはメソッドが見つかるまで、buddy → Dog → Animal の順にチェックします。
複数ファイルによるクラス構成
親クラスファイル (Animal.lua):
local Animal = {}
Animal.__index = Animal
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
function Animal:speak()
print(self.name .. " makes a sound")
end
return Animal子クラスファイル (Dog.lua):
local Animal = require("Animal")
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = {name = name}
setmetatable(obj, Dog)
return obj
end
return Dogメインファイルでの使用:
local Dog = require("Dog")
local buddy = Dog:new("Buddy")
buddy:speak() -- 出力: Buddy makes a sound自分で試してみよう
-- main.lua: エントリポイント
local Dog = require('Dog')
-- 入力から犬の名前を読み込む
local name = io.read()
-- TODO: 指定された名前でDogインスタンスを作成する
-- TODO: 犬のインスタンスで :speak() メソッドを呼び出す
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。