回复“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
水平不够,只能看懂没法翻译
Global site tag (gtag.js) - Google Analytics