Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 引用父类中的子类的模板_Oop_D - Fatal编程技术网

Oop 引用父类中的子类的模板

Oop 引用父类中的子类的模板,oop,d,Oop,D,在D中,是否可以从父类中引用子(继承)类 我试过这样的方法: abstract public @property typeof(this)[] sequence(); 希望typeof(this)将解析为重写该方法的子类,而不是父类;但事实并非如此。有办法吗 提前谢谢。听起来像是你在找的 但是,请注意,上面的sequence不是一个虚拟函数,而且模板是在基类的上下文中实例化的。为了向用户提供一个简单的界面,您可能希望转到一个专门的函数。这可以是虚拟函数(在这种情况下,您需要强制转换函数的返回值

在D中,是否可以从父类中引用子(继承)类

我试过这样的方法:

abstract public @property typeof(this)[] sequence();
希望
typeof(this)
将解析为重写该方法的子类,而不是父类;但事实并非如此。有办法吗


提前谢谢。

听起来像是你在找的

但是,请注意,上面的
sequence
不是一个虚拟函数,而且模板是在基类的上下文中实例化的。为了向用户提供一个简单的界面,您可能希望转到一个专门的函数。这可以是虚拟函数(在这种情况下,您需要强制转换函数的返回值),也可以是子类中的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;
}
虚拟调用可能看起来最吸引人,因为如果子类未能实现
sequenceImplVirtual
,它会导致编译错误。但是请注意,重写函数并不声明返回一个
派生的[]
,如果您错误地返回了
或其他非派生自
派生的
类,则程序将出错。显式强制转换有效地隐藏了这一点。一个稍微详细一点的程序可以测试这一点:

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
返回无效值,则在运行时会出现易于理解的断言错误

另一方面,duck类型的解决方案并不表示您在使用它之前忘记实现
sequenceImplDuck
。但是,由于它只执行安全强制转换(
cast(T)this
),编译器保证返回值确实是一个
派生的[]

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
,编译器将不会给出
派生的
派生的2
未正确实现所需函数的指示,虚拟呼叫将使用哪个。

听起来像是您在寻找的

但是,请注意,上面的
sequence
不是一个虚拟函数,而且模板是在基类的上下文中实例化的。为了向用户提供一个简单的界面,您可能希望转到一个专门的函数。这可以是虚拟函数(在这种情况下,您需要强制转换函数的返回值),也可以是子类中的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;
}
虚拟调用可能看起来最吸引人,因为如果子类未能实现
sequenceImplVirtual
,它会导致编译错误。但是请注意,重写函数并不声明返回一个
派生的[]
,如果您错误地返回了
或其他非派生自
派生的
类,则程序将出错。显式强制转换有效地隐藏了这一点。一个稍微详细一点的程序可以测试这一点:

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
返回无效值,则在运行时会出现易于理解的断言错误

另一方面,duck类型的解决方案并不表示您在使用它之前忘记实现
sequenceImplDuck
。但是,由于它只执行安全强制转换(
cast(T)this
),编译器保证返回值确实是一个
派生的[]

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
的情况下编译,编译器将不会给出
派生的
派生的
没有正确实现所需函数的指示,而虚拟调用会这样做。

如果您有一堆子类,一个包含所有这些元素的列表,以及基类的类型,对于每个元素,
sequence
会返回什么?每个都有不同的类型?静态类型不是这样工作的。尽管您可以使用标准的多态性方法得到您想要的。你到底想做什么?好吧,这并不是我想做的,但是为了解释,它是有效的:比如说我想要一个像SerializedElement这样的抽象类,XMLElement和JSoneElement从中继承。我希望每个子类都有一个用于返回子元素的方法/属性,这些子元素显然属于同一个类。我将如何(如果这是可能的话)在SerializedElement中实现一个抽象方法,该方法返回子元素的任何类型的数组(XMLElement或JSONElement)?如果您有一堆子类,以及一个包含所有子类的列表,并且其类型为基类,那么您希望每个元素返回什么?每个都有不同的类型?静态类型不是这样工作的。尽管您可以使用标准的多态性方法得到您想要的。你到底想做什么?好吧,这并不是我想做的,但是为了解释,它是有效的:比如说我想要一个像SerializedElement这样的抽象类,XMLElement和JSoneElement从中继承。我希望每个子类都有一个用于返回子元素的方法/属性,这些子元素显然属于同一个类。我将如何(如果这是可能的话)在SerializedElement中实现一个抽象方法,该方法返回子元素的任何类型的数组(XMLElement或JSONElement)?