0

私の目標は、本格的な多重継承を備えたクラスを作成する標準的な方法と、他のクラスへの継承だけでなく、new()コンストラクターを介したそれら自身のインスタンスへの継承も可能にすることです。クラスまたはそのオブジェクトから欠損値を呼び出し、この値が関数である場合、オブジェクト/インスタンスではなく、後で使用するためにクラスに格納したいと考えています (同じ関数を大量に実装する場合のパフォーマンスの問題)クラスのインスタンスの量)。

現時点では、公式のチュートリアル シリーズ ( http://www.lua.org/pil/16.3.htmlcreateClass(...) )で言及されている関数と非常によく似た関数を使用して、ほぼ任意の数の親クラスから継承するクラスを作成しています。 :

-- look up for k in list of tables plist
local function search (k, plist)
    for i=1, #plist do
        local v = plist[i][k]     -- try i-th superclass
        if v then return v end
    end
end

local function createClass (...)
    local args = {...};
    local c = {};
    -- search all provided parent classes for variables/functions to inherit and include them
    -- could be done without including them (deeply nested inheritance might be an issue this way
    -- due to repeated search calls for each use of an inherited function)
    setmetatable(c, {__index = function (t, k)
        local v = search(k, args);
        t[k] = v;
        print(t, " ...looking for... ", k, v);
        return v;
    end})
    return c;
end

新しく作成されたクラスに index-metamethod を渡します。このメソッドは、指定された欠落しているキーをすべての親で検索し、後で呼び出し元のクラスで使用できるように格納します。これは、ネストされた巨大な継承階層を検索する場合でも、目的として機能します。それでは、基本的なコンストラクターを持つ単純なクラスを紹介しましょう。

local P = {};
local MyClass = P;

function P.new ()
    local self = {};
    local priv = {};
    setmetatable(self, {__index = function (t, k)
        -- shouldn't this invoke __index-metamethod of P because P does not already have k
        -- at this stage of the program?
        local v = P[k];
        print(t, " ...looking for ... ", k, v);
        if(type(v) == "function") then
            -- ??? maybe do somethine else here to enforce __index of class P
        else
            t[k] = v;
        end
        return v;
    end});

    self.testSelf = function () print("testSelf") end;
    priv.testPriv = "testPriv!";

    function self.accessPriv ()
        return priv;
    end

    return self;
end

function P.TEST ()
    print("calling TEST");
end

この継承とクラスの実装を次のコードで__index呼び出すと、クラスの新しいインスタンスが作成されたときにクラスの -metamethod が呼び出されないことがわかります (出力されたテーブル アドレスを比較してください) __index。オブジェクトは、この時点でそのような値/関数を持たない (親) クラスから欠落している値/関数を要求します。__indexどうやら、この記述は、私を混乱させるクラス自体の -metamethod を呼び出しません。スクリプトのどの部分からでも、クラス/テーブルの欠損値が要求された場合は常に呼び出されると想定します。

  1. __index与えられた例で-metamethod がMyClass呼び出されないのはなぜですか?
  2. そして、どうすればそれを達成できますか (コードの変更をできるだけ少なくすることによって)?

あなたの提案は大歓迎です!

4

1 に答える 1

0

私はそれを完全に理解することなく答えを見つけました。クラスのコンストラクターを呼び出すときにnew、クラス自体を渡す必要があるようです。このようにして、クラスを表す自己変数を直接操作できます。object-metamethodで他の操作のためにクラスにアクセスできないのに、クラスとその親からクラスインスタンス/オブジェクトに継承できる理由については、まだ混乱が残っています__index

このクラス定義は最終的に仕事をします:

local P = {};
local MyClass = P;

-- must pass class itself while creating new object of it (don't know why...)
function P:new ()
    local pub = {};
    local priv = {};
    setmetatable(pub, {__index = function (t, k)
        local v = P[k];
        -- store functions into the class for later use (less duplicates)
        -- and all other inherited variables into the objects itself
        if (type(v) == "function")
            self[k] = v;
        else
            t[k]    = v;
        end
        return v;
    end});

    pub.testSelf = function () print("testSelf") end;
    priv.testPriv = "testPriv!";

    function pub.accessPriv ()
        return priv;
    end

    return pub;
end

function P.TEST ()
    print("calling TEST");
end
于 2014-04-21T11:27:36.610 に答える