Menu
Coddy logo textTech

メソッドの継承

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
end

Dogを作成し、親のメソッドを呼び出したときに何が起こるか見てみましょう:

local buddy = Dog:new()
buddy:breathe()  -- 出力: 呼吸しています...

Dogクラスは:breathe()を定義していませんが、正常に動作します。Luaはまずbuddyを確認し、何も見つからないため、次にDogを確認しますが、そこでも見つからず、最終的にAnimalの中でそれを見つけます。この自動的なメソッド継承により、共有される振る舞いを親クラスに一度書くだけで、すべての小クラスが即座にその恩恵を受けることができます。

challenge icon

チャレンジ

簡単

メソッドの継承を実際に確認するために、シンプルな生物の階層構造を構築しましょう!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はメソッドが見つかるまで、buddyDogAnimal の順にチェックします。

複数ファイルによるクラス構成

親クラスファイル (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() メソッドを呼び出す
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Object Oriented Programmingのすべてのレッスン