在D中,是否可以从父类中引用子(继承)类?
我试过这样的事情:
abstract public @property typeof(this)[] sequence();
希望typeof(this)
将解析为覆盖该方法而不是父类的子类;但事实并非如此。有没有办法做到这一点?
提前致谢。
答案 0 :(得分:3)
听起来像你在寻找template this parameters。
class Base { T[] sequence(this T)() { return null; } }
class Derived : Base {}
static assert(is(typeof((new Derived).sequence()) == Derived[]));
但是,请注意,上面的sequence
不是虚函数,而且模板也是在基类的上下文中实例化的。要为用户提供简单的界面,您可能希望转发到专门的功能。这可以是一个虚函数(在这种情况下你需要转换函数的返回值),或者是子类中的duck-typed函数:
class Base {
T[] sequence(this T)() {
// Virtual call, requires unsafe cast of return type.
return cast(T[])sequenceImplVirtual();
// Non-virtual call, requires safe cast of this reference
// and will fail if the subclass doesn't implement it correctly.
return (cast(T)this).sequenceImplDuck();
}
abstract Base[] sequenceImplVirtual();
}
class Derived : Base {
Derived[] sequenceImplDuck() {
return [this];
}
override Base[] sequenceImplVirtual() {
return [this];
}
}
unittest {
Derived[] arr = (new Derived).sequence;
}
虚拟调用可能看起来最具吸引力,因为如果子类无法实现sequenceImplVirtual
,则会产生编译错误。但是请注意,重写功能并不声称会返回Derived[]
,如果您错误地返回了Base
或其他不是从Derived
派生的类该程序将是段错误的。明确的演员有效地隐藏了这一点。一个稍微冗长的程序可以测试这个:
T[] sequence(this T)() {
import std.algorithm.searching : all;
auto result = sequenceImplVirtual();
assert(result.all!((Base a) => a is null || cast(T)a !is null));
return cast(T[])result;
}
如果sequenceImplVirtual
返回无效值,这将在运行时提供易于理解的断言错误。
sequenceImplDuck
。但是,由于它只执行安全转换(cast(T)this
),编译器保证返回值确实是Derived[]
:
class Base {
T[] sequence(this T)() {
return (cast(T)this).sequenceImplDuck();
}
}
class Derived : Base {
// Note: wrong return type.
// Will fail to compile when you call sequence().
Base[] sequenceImplDuck() {
return [this];
}
}
class Derived2 : Base {
// Note: No implementation.
// Will fail to compile when you call sequence().
}
unittest {
Derived[] arr = (new Derived).sequence;
auto d = new Derived2;
auto arr2 = d.sequence;
}
使用-unittest
编译时,上述操作会失败,但如果您注释掉unittest,或者编译时没有-unittest
,编译器将不会指示Derived
或{{1}没有正确实现所需的功能,虚拟呼叫将会。