Menu
Coddy logo textTech

共有と固有

CoddyのLuaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 35/70。

継承を扱う際は、それぞれのデータがどこに存在するのかを理解することが重要です。一部の属性は共有されます。親で定義され、すべての子からアクセスできます。一方、固有のものもあります。子クラスまたはインスタンスで特別に作成されます。

次の階層を考えてみましょう:

local Animal = {}
Animal.__index = Animal
Animal.kingdom = "Animalia"  -- 共有: クラスに定義されている

function Animal:new(name)
    local obj = {name = name}  -- 固有: 各インスタンスに保存されている
    setmetatable(obj, Animal)
    return obj
end
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
Dog.sound = "bark"  -- すべての Dog で共有される

function Dog:new(name, breed)
    local obj = Animal.new(Animal, name)
    obj.breed = breed  -- 固有: 各 Dog は独自の breed を持つ
    setmetatable(obj, Dog)
    return obj
end

Dog インスタンスを作成すると、一部の値はオブジェクト上に直接存在し、その他の値は lookup chain を通じて found されます:

local rex = Dog:new("Rex", "German Shepherd")

-- このインスタンスに固有(rex に格納)
print(rex.name)    -- "Rex"
print(rex.breed)   -- "German Shepherd"
-- 共有(ルックアップ経由で見つかった)
print(rex.sound)   -- "bark" (Dogから)
print(rex.kingdom) -- "Animalia" (Animalから)

重要な違いは、コンストラクターでobjに割り当てられたフィールドは各インスタンス固有であるのに対し、クラステーブル上で直接定義されたフィールドは、そのクラスとその子クラスのすべてのインスタンス間で共有されるという点です。

challenge icon

チャレンジ

簡単

Creature クラスと Dragon クラスのシステムを構築し、継承階層を通じてデータがどのように流れるかを見ていきましょう。すべてのインスタンスで共有される属性と、個々のオブジェクトごとに固有の属性を実際に確認できます。

コードを次の3つのファイルに分けて整理します。

  • Creature.lua:共有 class レベル属性 world = "Fantasy Realm" を定義する親 class を作成します。この属性はすべての creatures で共有されます。また、creature の名前をインスタンス属性として保存する :new(name) コンストラクターを含めます。
  • Dragon.lua:Creature から inherits する child class を定義します。すべての dragons で共有される共有 class レベル属性 element = "fire" を Add します。:new(name, color) コンストラクターでは、まず名前について親コンストラクターを Call し、その後、各 dragon の固有インスタンス属性として color を Add します。
  • main.lua:2体の異なる dragons を Create し、それらの属性を調べて、共有データと固有データの違いを demonstrate します。

2つの入力を受け取ります。

  1. カンマで区切られた First dragon の名前と色(例:Smaug,red
  2. カンマで区切られた Second dragon の名前と色(例:Draco,gold

main ファイルで、それぞれの名前と色を使って両方の dragons を Create します。次に、following の情報をこの正確な順序で出力します。

  1. First dragon の name
  2. First dragon の color
  3. Second dragon の name
  4. Second dragon の color
  5. First dragon の element(Dragon class から共有)
  6. Second dragon の element(Dragon class から共有)
  7. First dragon の world(Creature class から共有)

たとえば、入力が Smaug,redDraco,gold の場合、出力は次のようになります。

Smaug
red
Draco
gold
fire
fire
Fantasy Realm

namecolor は各 dragon で異なる(固有のインスタンス属性)のに対し、elementworld は両方で同じ(lookup chain を通じて found される共有 class 属性)であることに注目してください。

自分で試してみよう

-- main.lua: ドラゴンを作成し、共有属性と固有属性を示す

local Dragon = require('Dragon')

-- 最初のドラゴンの入力を読み取る (name,color)
local input1 = io.read()
-- 2番目のドラゴンの入力を読み取る (name,color)
local input2 = io.read()

-- TODO: 最初の入力を解析して name と color を抽出する
-- Hint: パターン "([^,]+),([^,]+)" で string.match を使用する

-- TODO: 2番目の入力を解析して name と color を抽出する

-- TODO: name と color で最初のドラゴンを作成する

-- TODO: name と color で2番目のドラゴンを作成する

-- TODO: 以下を順番に出力する:
-- 1. 最初のドラゴンの name
-- 2. 最初のドラゴンの color
-- 3. 2番目のドラゴンの name
-- 4. 2番目のドラゴンの色
-- 5. 1番目のドラゴンの属性(Dragonクラスから共有)
-- 6. 2番目のドラゴンの属性(Dragonクラスから共有)
-- 7. 1番目のドラゴンの世界(Creatureクラスから共有)
quiz icon腕試し

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

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Luaオンラインコンパイラ