2009-09-11 5 views
4

나는이 일을하고 싶습니다 : 나는 불완전한 형식을 반환 할 수 없기 때문에 물론C++의 기본 클래스 메서드에서 파생 클래스를 반환 할 수 있습니까?

class Derived; 

class Base { 
    virtual Derived f() = 0; 
}; 

class Derived : public Base { 
}; 

이 작동하지 않습니다. 하지만 불완전한 타입을 상속받을 수 없기 때문에베이스 이전에 Derived를 정의 할 수도 없습니다. 나는 템플릿을 임시 해결책으로 사용할 수 있다고 추측한다. (Base에 대한 템플릿 인수로 파생 됨), 실제로 일을하는 것은보기 흉한 방법이다. 다른 방법이 있을까요?

정교화 : 나는 raytracer를 작성하고 있으며 각 Shape 클래스에는 경계 상자를 반환하는 함수가 있습니다. 그러나 BBox를 Shape의 하위 클래스로 만들었으므로이를 시각화 할 수 있습니다. 이 나쁜 디자인입니까?

+2

그러나 당신은 그렇지 않습니다. 함수의 선언 시점에서 불완전한 형식을 반환하는 함수를 선언하는 것일뿐입니다. 괜찮을거야. 내 대답보기 (http://stackoverflow.com/questions/1412348/is-it-possible-to-return-a-derived-class-from-a-base-class-method-in-c/1412451#1412451) . – sbi

답변

9

질문에 아무 문제가 없습니다. 이

class Derived; 

class Base { 
    virtual Derived f() = 0; 
}; 

class Derived : public Base { 
    virtual Derived f() {return Derived();} 
}; 

잘 컴파일해야합니다. 그러나 'Base :: f()'호출자는 정의의 '파생 됨'을 확인해야합니다.

+0

doh - 빈 정의 f()를 클래스 선언에 넣었습니다. 컴파일 오류가 발생했습니다. 나는 이것이 존재하기를 기대하기 때문에 이것이 존재하지 않는 문제를 보는 경우라고 생각합니다. – int3

+0

편집 : "기본 클래스 선언" – int3

+0

@splicer : 당신도 이것을 할 수 있습니다 ('Base :: f()'구현). 유일한주의 사항은 구현체가'Derived'의 정의를보아야한다는 것입니다. 따라서 클래스를 "Derived"(또는'Derived.h'를 포함하는'Base.cpp')로 옮겨야합니다. 컴파일러의 POV는 동일합니다). – sbi

8

당신은 포인터 (또는 참조) 사용할 수 있습니다

class Derived; 

class Base { 
    virtual Derived *f() = 0; 
}; 

class Derived : public Base { 
}; 

를하지만 나에게 코드 냄새입니다. 이 클래스에서 상속받은 사람은 왜 다른 파생 클래스에 대해 알아야합니까? 사실 기본 클래스가 derivee 클래스에 관심을 가져야하는 이유는 무엇입니까?

상황에 따라 나쁜 디자인의 신호가 될 수 있음을 알아야합니다. 바운딩 박스는 Shape에서 파생된다는 것이 맞지만 Shape에는 바운딩 박스를 반환하는 함수가 있기 때문에 바운딩 박스에는 자체를 반환하는 함수가 있습니다.

나는 최선의 해결책 확실하지 않다,하지만 당신은 완전히 BBox 별도의 클래스를 만들고, 아마도 그것을와 유사한 기능을 줄 수 : 경계 상자와 같은 크기로 class Box : public Shape를 구성 할 Shape *as_shape(void) const을.

나는 여전히 더 좋은 방법이 있다고 느낀다. 그러나 나는 시간이 없어, 다른 누군가가 더 나은 해결책을 생각할 것이라고 확신한다.

+0

그렇다면 이상한 메모리 관리, 함수 내부 할당, 외부에서의 삭제가 필요할 것입니다. 함수에 대한 참조를 전달할 수 있다고 생각합니다. 상세 설명 : 광선 추적기를 작성하고 있으며 각 Shape 클래스에는 경계 상자를 반환하는 함수가 있습니다. 그러나 BBox를 Shape의 하위 클래스로 만들었으므로이를 시각화 할 수 있습니다. 이 나쁜 디자인입니까? – int3

+0

그 대답을했지만 다른 사람들에게 기회를주기 위해 질문을 편집 할 것입니다. – GManNickG

3

자료에 대해 알 필요하지 않도록 내가하는 자료에 대한 포인터를 반환과 함께 가고 싶어 파생 이상 나타나서 무엇 :

class Base { 
    virtual Base *f() = 0; 
}; 

class Derived : public Base { 
    virtual Base *f(); 
}; 

Base *Derived::f() { 
    Derived *r = new Derived; 
    return r; 
} 
4

왜 그냥하지 :

class Base { 
    virtual Base *f() = 0; 
}; 
2

다른 사람들이 지적했듯이 코드 샘플은이 될 수 있지만 아마도 f()에서 기본 클래스에 대한 포인터를 반환한다는 의미입니다.당신의 정교화에

, 당신은 경계 상자 모양의 서브 클래스는 언급하지만, 문제가있는 것입니다 :

class Shape{ 
    virtual void draw() = 0; // You can draw any shape 
}; 
class BBox: public Shape{ 
    virtual void draw(); // This is how a bounding box is drawn 
}; 

class BoundedShape: public Shape{ 
    virtual BBox* getBoundingBox() = 0; // Most shapes have a bounding box 
}; 

class Square: public BoundedShape{ 
    virtual void draw(); 
    virtual BBox* getBoundingBox(); // This is how Square makes its bounding box 
}; 

응용 프로그램을 :

class Shape{ 
    virtual Shape* getBoundingBox() = 0; 
}; 

class Square: public Shape{ 
    virtual Shape* getBoundingBox(); 
}; 
class BBox: public Shape{ 
    virtual Shape* getBoundingBox(); // Whoops! What will BBox return? 
}; 

주위 책임의 일부를 이동할 수는 이제는 BoundedShape*의 콜렉션을 보유해야하고 때로는 BBox*을 요청해야합니다.

4

템플릿에 대한 귀하의 개념이 반드시 나쁜 것은 아닙니다. 당신이 말하는 것을 Curiously Recurring Template Pattern이라고합니다.

예 :

"나는 불완전한 형식을 반환 할 수 없기 때문에이 작동하지 않습니다 물론."
#include <iostream> 

template <typename T> 
struct Base 
{ 
    virtual T* foo() = 0; 
}; 

struct Derived : Base<Derived> 
{ 
    virtual Derived* foo() { return this; } 
}; 
관련 문제