Lua オブジェクト指向プログラミング　メタテーブルを使用する場合としない場合

Luaはオブジェクト指向プログラミングをサポートしている
現在使用しているオブジェクト指向プログラミングの実装方法をまとめておく

#メタテーブルを使用しない場合

###クラスの実装とインスタンス化

```Lua
Class = {}
function Class.new()
    local obj = {}
    obj.func = function(self)
                   --関数の処理
               end;
    return obj
end

local instance = Class.new()
instance:func()
```
メタテーブルを使用しない場合はnewによって返すテーブルの中に関数を入れてあげます。
継承とオーバーライドは以下の通りです。

###継承・オーバーライド
```Lua
Child = {}
function Child.new()
    local obj = Class.new()
    obj.func = function(self) --オーバーライド
                   --関数の処理
               end;
    return obj
end
```
returnするテーブルには親クラスのインスタンスを入れてあげます。
この実装の問題点は新たにインスタンスを作成するたびにメソッドを初期化する必要がある点です。



#メタテーブルを使用する場合
###instance関数
```lua
function instance(class, super, ...)
    local self = (super and super.new(...) or {})
    setmetatable(self, {__index = class})
    setmetatable(class, {__index = super})
    return self
end
```

子クラスの __index に親クラスを、インスタンスの __index に子クラスを設定してあげます。
これによりインスタンス(self)に存在しないキーにアクセスした時、クラスとその親クラスから探してくることができます。

__indexやmetatableについて詳しく知りたい方は、[こちら](https://www.lua.org/pil/13.4.1.html)を参考にしてください


###クラスの実装
```lua
Class = {
    new = function(val1,val2)
        local obj = instance(Class)

        --ここでメンバ変数を宣言
        obj.m_val1 = val1
        obj.m_val2 = val2

        return obj
    end;

    func = function(self)
        -- 処理
    end;
}
```

クラスの宣言、実装は上記のように行います。


```lua
local temp = Class.new(1,2)
temp:func()
```
new関数を呼んであげればinstance関数によって作成されたインスタンスを返してくれます。
このインスタンスには__indexにクラスとその親クラスが設定してあるため、実装したクラスの関数を呼び出すことができます。

ちなみに

```lua
temp.func(temp)
temp:func()
```

は共に自分自身をメソッドに渡す処理です。下の書き方は上の書き方の省略形ですね。


###継承

```lua
--親クラス
Parent = {
    new = function(val1,val2)
        local obj = instance(Parent)
        
        --ここでメンバ変数を実装
        obj.m_val1 = val1
        obj.m_val2 = val2

        return obj
    end;

    parentFunc = function(self)
        -- 処理
    end;
}

--子クラス
Child = {
    new = function(val1,val2)
        local obj = instance(Child,Parent,val1,val2)

        --ここでメンバ変数を実装
        
        return obj
    end;

    func = function(self)
        Parent.parentFunc(self)  --親クラスのメンバ関数を呼ぶ
    end;
}    
```

継承は上記のように行います。instance関数の引数に親クラスを与えてあげればよいです。
子クラス内で親クラスの関数を呼びたいときは```親クラス.関数名()```でアクセスしてください。


###オーバーライド
```lua
--親クラス
Parent = {
    new = function(val1,val2)
        local obj = instance(Parent)
        
        --ここでメンバ変数を実装
        obj.m_val1 = val1
        obj.m_val2 = val2

        return obj
    end;

    func = function(self)
        -- 処理
    end;
}

--子クラス
Child = {
    new = function(val1,val2)
        local obj = Parent.new(Child,Parent,val1,val2)
        return obj
    end;

    --オーバーライド
    func = function(self)
        -- 新しい処理
    end;
}    
```
オーバーライドをしたい時は子クラスに親クラスの関数を新たに定義します。

#速度について
[kengonakajima](https://github.com/kengonakajima/blog/blob/master/articles/luaoo.md)さんの[Lua OOPの速度比較](https://github.com/kengonakajima/blog/blob/master/articles/luaoo.md)によると
**metatableを使用する実装では、metatbleを使用しない実装に比べ大幅に速度が落ちるそうです。

追記
[まつもとゆきひろ コードの未来](https://books.google.co.jp/books?id=6cOjDwAAQBAJ&pg=PT174&lpg=PT174&dq=Lua+%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0+%E3%83%A1%E3%82%BF%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%A8%E3%81%97%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88&source=bl&ots=GYhfhSzIiq&sig=ACfU3U2apbs6CzmtdmfKLfMENfL41LdAvQ&hl=ja&sa=X&ved=2ahUKEwiflY68vLbmAhXK7WEKHXnkCOcQ6AEwBHoECAoQAQ#v=onepage&q=Lua%20%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%20%E3%83%A1%E3%82%BF%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%A8%E3%81%97%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88&f=false)では別の実装例が紹介されています。

参考
http://invalid-log.blogspot.com/2015/05/lua.html
https://github.com/kengonakajima/blog/blob/master/articles/luaoo.md