引用父项 class 中的子项 class 的模板
Template referring to child class within parent class
在 D 中,是否可以从父项 class 中引用子项(继承)class?
我试过这样的事情:
abstract public @property typeof(this)[] sequence();
希望 typeof(this)
能够解决覆盖该方法的子 class 而不是父 class;但事实并非如此。有办法吗?
提前致谢。
我觉得你在找 template this parameters。
class Base { T[] sequence(this T)() { return null; } }
class Derived : Base {}
static assert(is(typeof((new Derived).sequence()) == Derived[]));
但是请注意,上面的 sequence
不是虚函数,而且模板是在基 class 的上下文中实例化的。为了向用户提供一个简单的界面,您可能希望转发到一个专门的函数。这可以是一个虚函数(在这种情况下你需要转换函数的 return 值),或者是 subclass:
中的 duck 类型函数
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;
}
虚拟调用可能看起来最诱人,因为如果 subclass 未能实现 sequenceImplVirtual
,它会给出编译错误。但是请注意,覆盖函数并未声明 [=42=] a Derived[]
,如果您错误地 return a Base
或其他未派生的 class从 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
return 是一个无效值,这将在运行时给出一个易于理解的断言错误。
另一方面,duck 类型的解决方案在您使用它之前不会表明您忘记实施 sequenceImplDuck
。但是,由于它只进行安全转换 (cast(T)this
),编译器保证 return 值确实是 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
或Derived2
没有正确实现所需的功能,而虚拟调用会。
在 D 中,是否可以从父项 class 中引用子项(继承)class?
我试过这样的事情:
abstract public @property typeof(this)[] sequence();
希望 typeof(this)
能够解决覆盖该方法的子 class 而不是父 class;但事实并非如此。有办法吗?
提前致谢。
我觉得你在找 template this parameters。
class Base { T[] sequence(this T)() { return null; } }
class Derived : Base {}
static assert(is(typeof((new Derived).sequence()) == Derived[]));
但是请注意,上面的 sequence
不是虚函数,而且模板是在基 class 的上下文中实例化的。为了向用户提供一个简单的界面,您可能希望转发到一个专门的函数。这可以是一个虚函数(在这种情况下你需要转换函数的 return 值),或者是 subclass:
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;
}
虚拟调用可能看起来最诱人,因为如果 subclass 未能实现 sequenceImplVirtual
,它会给出编译错误。但是请注意,覆盖函数并未声明 [=42=] a Derived[]
,如果您错误地 return a Base
或其他未派生的 class从 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
return 是一个无效值,这将在运行时给出一个易于理解的断言错误。
另一方面,duck 类型的解决方案在您使用它之前不会表明您忘记实施 sequenceImplDuck
。但是,由于它只进行安全转换 (cast(T)this
),编译器保证 return 值确实是 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
或Derived2
没有正确实现所需的功能,而虚拟调用会。