回复“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
水平不够,只能看懂没法翻译
|

