ひとモノBLOG

03 « 2017 / 04 » 05
Sun Mon Tue Wed Thu Fri Sat
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 - - - - - -
profile
SHOO
  • SHOO
  • 機械系の学生。の割にプログラミングとかのほうが得意だったり。
  • RSS
links
BLOG内検索
Adds by DTI Blog

メンバ関数ポロロッカ
2008/12/11(木) [01:23:49]

D言語で遊んでみました。
気色の悪いハックをしようと思ったらC++並みに面白いことができますね。

今回のテーマは、「メンバ関数ポロロッカ」
メンバ関数を逆流させるというあほなことをやってみました。
普通、オーバーライドした関数からオーバーライドされた関数を呼び出すことは簡単に可能です
super.overridedFunc();
みたいなことをすれば呼べます
逆に、

オーバーライドされた関数からオーバーロードした関数を呼び出す…ということは可能でしょうか?

・クラス1のメンバ関数の処理
・・クラス2のメンバ関数の処理
・・・クラス3のメンバ関数の処理
・・・クラス3のメンバ関数の終了処理
・・クラス2のメンバ関数の終了処理
・クラス1のメンバ関数の終了処理

このような感じに逆順に呼び出していく…それが「メンバ関数ポロロッカ」
名前は適当にさっき考えた。他に呼び方あるかもしれないけど知らない。

import std.stdio;

class Super
{
    void func()
    {
        writef("<1");
        writef("1>");
    }
}
class D2: Super
{
    override void func()
    {
        writef("<2");
        super.func();
        writef("2>");
    }
}
class D3: D2
{
    override void func()
    {
        writef("<3");
        super.func();
        writef("3>");
    }
}
void main()
{
    auto d3 = new D3;
    d3.func;
    writefln("");
}

<3<2<11>2>3> この逆をやります。
つまり、何とかして
<1<2<33>2>1> この結果を得ようという試みです。できるだけスマートに。

続きは以下から。 腕に覚えのある人は試してみてください。

今回作ったコードはこんな感じ。非常に危険な香りが漂うプログラムです。

import std.stdio;

class Super
{
    void funcMain(void delegate() driven)
    {
        writef("<1");
        driven();
        writef("1>");
    }
    final void func()
    {
        static class Temp
        {
            // この辺がみそにしてキモイところ
            static union DGSelf
            {
                struct
                {
                    void* ptr, funcptr;
                }
                void delegate(void delegate()) dg;
            }
            DGSelf dgSelf;
            void delegate() dgChild;
            this(Super s, void* selffuncptr, void delegate() childdg)
            {
                dgSelf.ptr = cast(void*)s;
                dgSelf.funcptr = selffuncptr;
                dgChild = childdg;
            }
            void fn()
            {
                dgSelf.dg(dgChild);
            }
        }
        static void pororoca(Super s, void delegate() ch, ClassInfo ci)
        {
            // この辺とか超あやしい
            // Object.classinfo.vtbl.lengthでfuncMainのfuncptrを探す
            scope t = new Temp(s, ci.vtbl[Object.classinfo.vtbl.length], ch);
            if (ci.vtbl[Object.classinfo.vtbl.length]
                is Super.classinfo.vtbl[Object.classinfo.vtbl.length])
            {
                t.fn();
            }
            else
            {
                pororoca( s, &t.fn, ci.base);
            }
        }
        void nullfunc(){}
        pororoca(this, &nullfunc, this.classinfo);
    }
}
class D2: Super
{
    override void funcMain(void delegate() driven)
    {
        writef("<2");
        driven();
        writef("2>");
    }
}
class D3: D2
{
    override void funcMain(void delegate() driven)
    {
        writef("<3");
        driven();
        writef("3>");
    }
}
class D4: D3
{
    override void funcMain(void delegate() driven)
    {
        writef("<4");
        driven();
        writef("4>");
    }
}
void main()
{
    auto s = new Super;
    s.func();
    writefln("");
    auto d2 = new D2;
    d2.func();
    writefln("");
    auto d3 = new D3;
    d3.func();
    writefln("");
    auto d4 = new D4;
    d4.func();
    writefln("");
}

結果はこちら <11>
<1<22>1>
<1<2<33>2>1>
<1<2<3<44>3>2>1>

一応できました。
非常に脆そうなコードです。少し書き換えただけでバグが発生しそうな。
なんかもうちょっとやり方なかったのかな…

誰かエロいひと、がんばってみませんか?


rel="prev"<<Tango、UnicodeBomを更新 | ホーム |

この記事に対するトラックバック

この記事のトラックバックURL

この記事に対するコメント

この記事にコメントする

管理者にだけ表示を許可する
| HOME |