回复“mixin模拟多继承”
qiezi
2007-11-11
论坛回复坏掉了,先回复在这。批评一下,经常这样可不行咯,这应该算是比较大的运维事故。
必须mixin模板?这是一个限制呀,通常大家都是写成类的,在类上面多继承。。。 我好像没看到程序调用到ctor和dtor,mixin模板本身是可以直接用this/~this的,它会按照mixin的顺序来调用,不需要自己实现ctor/dtor,D里面早就是用mixin来代替多继承了。 |
|
oldrev
2007-11-11
如果用类多继承就又回到C++了,当然也不是不能实现,可以用__traits(allMembers)把假超类所有的成员加到被继承的类中。不过这样作限制很大,不能有函数重载(__traits 的限制),被继承的类只能从 Object 派生(主类倒是没限制),而且 this/~this 无法自动处理。
很久以前我已经实验过了,尽管 this/~this 都可以出现在模板里,但是如果子类有this()的话,模板里的 this() 会被隐藏掉。只有 ~this 会被自动调用,可能因为 ~this 是虚函数的原因吧。 一个具体的例子: import std.stdio; template M() { this() { writefln("M.this()"); } ~this() { writefln("M.~this()"); } } class Foo { mixin M!(); this() { writefln("Foo.this()"); } ~this() { writefln("Foo.~this()"); } } void main() { Foo f = new Foo; } 输出: Foo.this() Foo.~this() M.~this() |
|
oldrev
2007-11-11
不过我倒是想了个辙:
class Foo { mixin M!() mm; this() { mm._ctor(); //调用 M.this writefln("Foo.this()"); } ~this() { writefln("Foo.~this()"); } } |
|
qiezi
2007-11-11
果然是这样,没注意这个。
|
|
oldrev
2007-11-11
用了一大陀元编程,终于搞定了:
/** TupleMixin 演示程序, DMD2.007/GDC0.24 测试通过 Written in the D programming language 1.0 作者: oldrev <oldrev@gmail.com> Copyrights: */ import std.stdio; //PredT 参数的作用是让你能够在每个模板混入之前对它进行处理, //比如可以在混入前用 static assert 检查是否有特定的成员 //总而言之,PredT 给你机会控制混入时的细节。 template MixinTuple(alias PredT, L...) { mixin PredT!(L[0]); static if(L.length > 1) mixin MixinTuple!(PredT, L[1..$]); } //PredT 实例1,直接混入 template DirectMixinPred(alias X) { mixin X!(); } //PredT 实列2,混入且检查模板X是否有 ctor 成员函数 template MixinAndCheckCtorPred(alias X) { static assert(is(typeof(X!().ctor))); //检查 X 是否有成员 ctor mixin X!(); } class Mixinable(SuperClass, P...) : SuperClass { private const string InitCode = "private void initAllMixins() {"; //PredT 3,混入且产生同名 alias template MixinWithAliasPred(alias X) { mixin("mixin X!() " ~ (X.stringof)[0..$-2] ~ ";"); //去掉模板名称后的 '()' } mixin MixinTuple!(MixinWithAliasPred, P); private template MakeInitCode(TL...) { static if(TL.length == 0) const string MakeInitCode = ""; else { static if(is(typeof(mixin(TL[0].stringof[0..$-2] ~ "._ctor")))) //"HasMember" 惯用法 { const string MakeInitCode = TL[0].stringof[0..$-2] ~ "._ctor();\n" ~ MakeInitCode!(TL[1..$]); } else const string MakeInitCode = MakeInitCode!(TL[1..$]); } } protected this() { const string Code = MakeInitCode!(P); mixin(Code); } } /////////////////////////////////////////////////////////////////////////////// template Policy() { this() { writefln("Policy.this()"); } ~this() { writefln("Policy.~this()"); } void bar(T)(T x) { writefln("bar()"); } } template Policy2() { this() { writefln("Policy2.this()"); } ~this() { writefln("Policy2.~this()"); } void foo() { writefln("Policy2.foo"); } } class SuperBar //超类,或者叫基类 { this() { writefln("SuperBar.this()"); } } // Mixinable 用法演示——模拟多继承 // Foo 类是组合 Policy, Policy2 和 基类 SuperBar 的结果 class Foo : Mixinable!(SuperBar, Policy, Policy2) { this() { writefln("Foo.this()"); } void foo() { writefln("Foo.foo"); } ~this() { writefln("Foo.~this()"); } } //MixinTuple 也可以直接使用 /* class Foobar : SuperBar { mixin MixinTuple!(DirectMixinPred, Policy, Policy2); } */ void main() { Foo f = new Foo; f.foo; f.bar(3); } |
|
qiezi
2007-11-11
咳咳。。。不错。有没有考虑下构造函数的参数如何传递?这个估计比较麻烦。
|
|
oldrev
2007-11-11
qiezi 写道 咳咳。。。不错。有没有考虑下构造函数的参数如何传递?这个估计比较麻烦。
太贪心了吧,呵呵。构造函数的参数似乎没什么太大意义,尤其是对于模板而不是类来说。这个程序只能说是一个实验,真正用面向 Policy 设计的程序应该是这个样子的: class Button(alias DrawingAspect, alias MsgProcAspect) { mixin DrawingAspect!(arguments); mixin MsgProcAspect!(arguments); } |
|
shizhusz110110
2007-11-14
能不能详细翻译几篇关于模板的文章.还不知道模板可以这样用.才学
D.不好意思. |
|
oldrev
2007-11-14
水平不够,只能看懂没法翻译
|