2017-10-19 15 views
0

D에서 부모 클래스 내에서 자식 (상속) 클래스를 참조 할 수 있습니까?부모 클래스 내의 자식 클래스를 참조하는 템플릿

나는이 같은 시도 :

abstract public @property typeof(this)[] sequence(); 

typeof(this) 대신 상위 클래스의 메소드를 오버라이드 (override) 하위 클래스에 해결할 것이라고 희망을; 그러나 그렇지 않습니다. 그렇게 할 수있는 방법이 있습니까?

미리 감사드립니다.

+0

자식 클래스가 많이 있고 기본 클래스의 유형이 모두 들어있는 목록이있는 경우 각 요소에 대해'sequence'가 무엇을 반환 할 것으로 기대합니까? 각각 다른 유형? 그것은 정적 타이핑이 작동하는 방식이 아닙니다. 비록 당신이 표준 다형성 수단을 사용하여 원하는 것을 얻을 수있을지라도. 실제로 무엇을하고 싶습니까? – weltensturm

+0

글쎄,이게 내가하고 싶은 일이 아니지만, 설명을 위해서 작동한다. XMLElement와 JSONElement가 상속받은 SerializedElement와 같은 추상 클래스가 필요하다고 해봅시다. 나는 각 자식 클래스에 자식 요소를 반환하기위한 메서드/속성을 갖고 싶습니다. 자식 요소는 분명히 같은 클래스에 속할 것입니다. 어떻게하면 (심지어 가능하다면) 자식 (XMLElement 또는 JSONElement) 유형의 배열을 반환하는 SerializedElement의 추상 메서드를 구현할 수 있습니까? –

답변

3

찾고있는 소리가 template this parameters입니다.

class Base { T[] sequence(this T)() { return null; } } 
class Derived : Base {} 
static assert(is(typeof((new Derived).sequence()) == Derived[])); 

참고 그러나, sequence는 상기 템플릿이 상기베이스 클래스의 컨텍스트에서 인스턴스화 것이 가상 함수 아니며,. 사용자에게 간단한 인터페이스를 제공하려면 특수 기능으로 전달해야 할 수 있습니다. 가상 호출이 가장 매혹적인 보일 수 있습니다

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없이 컴파일하면 컴파일러는 Derived 또는 Derived2이 가상 호출이 필요한 함수를 올바르게 구현하지 않는다는 표시를 제공하지 않습니다.