引用父项 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编译,编译器不会提示DerivedDerived2 没有正确实现所需的功能,而虚拟调用会。