2011-01-16 4 views
0

GUI 시스템을 구축하고 기본 "GUIcontrol"클래스에서 파생 된 여러 GUI 구성 요소에 대한 몇 가지 클래스가 있습니다. 필자가 원하는 것은 모든 유형의 구성 요소를 반환하지만 해당 구성 요소 유형 (파생 클래스의 함수)에 특정한 기능으로 작업 할 수 있어야한다는 것입니다. 다형성 접근법은 기본 클래스에서 객체를 생성하지 않기 때문에베이스에서 모든 파생 함수를 선언해야한다는 문제가 될 것임을 알았습니다.다형성에 대한보다 깨끗한 코드

class GUIcontrol { 
    protected: 
    std::string _name; 
    // these two methods (along with name()) will be used by all types 
    virtual void position(/*parameters*/) 
    virtual void useImage(/*parameters*/) 

    // these should be only in derived types 
    virtual void setHotSpot(/*parameters*/); 
    virtual void setScrollButtons(/*parameters*/); 
    public: 
    std::string name(); 
    /*etc*/ 
} 

class GUIbutton : public GUIcontrol { 
    public: 
    void setHotSpot(/*parameters*/); 
} 

class GUIscrollBar : public GUIcontrol { 
    public: 
    void setScrollButtons(/*parameters*/); 
} 

GUIcontrol* GUIsystem::getControl(std::string name); 

이 문제는 내가 GUIbutton 또는 GUIscrollBar, 또는 기타 파생 GUI 클래스에 대한 모든 기능에 고유 한 기능을 더 추가하려는 경우, 나는 또한 기본 클래스에서 해당 가상 선언해야한다는 것입니다 컴파일러 아무튼 그래서 "setHotSpot"이 반환하는 기본 클래스의 멤버가 아닌 것과 같은 것에 불평하지 않습니다.

기본 클래스에는 모든 파생 클래스에 적용되는 멤버 함수가 있습니다 (예 : 위치를 지정해야하는 객체를 알려주는 것, 사용해야하는 이미지, 호출해야하는 것 등).하지만, 기본 클래스를 특정 파생 클래스에만 배타적으로 있어야하는 다른 함수로 채우고 싶습니다.

가상 함수를 계속 추가하면서 기본 클래스의 거대한 BLOB 객체로 끝납니다. 이것을보다 깨끗한 방법으로 설계 할 수 있습니까? static_cast/dynamic_cast를 사용하여 getControl()을 사용하여이 문제를 해결할 것인지 확실하지는 않지만이 문제를 해결할 수있는 다른 방법이 있는지 알고 싶습니다.

+5

다형 기본 클래스의 전체 점은 모든 가능한 파생 클래스에 공통적 인 모든 기능을 포함해야합니다. 'setHotSpot()'이 모든 파생 클래스에 대해 이해가되지 않는다면, generic 함수는 어떻게 다형성 방식으로 그것을 사용할 수있게 될까요? 제네릭 함수가 할 수있는 일종의 구체적인 예를 들어 줄 필요가 있다고 생각합니다. –

+0

더 큰 질문 인 IMO가 * 또 다른 * GUI 시스템을 만드는 이유는 무엇입니까? 이미 Qt, .NET, Java 또는 다른 많은 것들을 이미 재사용하지 않으시겠습니까? 나는 이것이 단지 학습을 위해서이기를 바랍니다. –

+0

@Austin : .NET과 Java는 GUI 시스템이 아닙니다. (그리고이 플랫폼 용으로 작성된 GUI 라이브러리는 C++로 작업하는 사람에게별로 도움이되지 않습니다.) – jalf

답변

4

에는 모든 컨트롤에 공통된 기능을위한 메소드가 있어야합니다.

한 유형의 컨트롤에만 의미가있는 기능을 사용하려는 경우 컨트롤의 유형이 올바른지 확인한 다음 해당 유형으로 캐스팅 할 수 있습니다.

+0

음, 그렇습니다. 그러나 유형을 확인하고 다이내믹 캐스팅을 수행해야하는 상황에 빠지면 설계가 이미 잘못되었을 수 있습니다. –

+2

@Oli - 디자인에서의 과도한 다운 캐스팅은 냄새를 나타낼 수 있지만 일부 파생물에만 제한된 기능을 갖춘베이스를 채우는 것은 훨씬 더 나쁜 냄새입니다. 전자가 의심스러운 디자인을 * 표시 할 수도 있지만, 후자는 * 나쁜 디자인입니다. 내가 사용했던 모든 UI 라이브러리는 새로운 위젯 유형을 확장하고 기본, 일반 위젯의 라디오 버튼 값을 확인하는 함수를 추가하지 않습니다. 어린애를 통해 검색 ALAWYS는 액세스가 필요한 특정 유형을 얻으려면 다운 캐스팅이 필요합니다. –

+1

@ 노아 : 나는 특정 보풀이 가득한 기초 수업에 대한 당신의 정서에 전적으로 동의합니다. 그러나, 나는 * 두 접근법이 엉터리 디자인을 나타내는 것이라고 생각합니다. 당신은 엉터리 API 디자인을 강요받지 않았다면 결코 이런 종류의 일을 위해 다운 캐스트를해서는 안됩니다. –

1

기본 클래스는 독점적으로 공통 기능입니다. 메서드가 다른 컨트롤에 대해 다르게 동작하게하려면 dynamic_cast을 사용합니다. 모든 컨트롤에 대해 동일한 기능을 사용하려면 가상 메서드를 사용하십시오.

가 문제입니다 : 내가 원하는 구성 요소의 모든 유형을 반환 한 기능을 가지고 있지만 (의 기능에 해당 구성 요소 유형에 특정한 기능을 작동 할 수있다

파생 된 클래스).

원하는 것은 동일하지만 다르게 취급하는 것입니다. 허. 나는 당신이 그 일을 어떻게 할 것인지 궁금해. 당신은 그들 모두를 동일하게 취급하고 싶은지, 아니면 다르게 취급하고 싶은지를 결정해야합니다.

+0

+1 익명 drive-by downvote. –

+0

모든 파생 클래스에 필요한 공통 함수를 사용하고 있음을 보여주는 코드가 업데이트되었습니다. –

+0

@JustChris : 예. 그러나 "일반"함수가 기본 클래스를 통해 유형별 함수에 액세스해야하는 이유는 설명하지 않았습니다! –

0

유형 검사 및 다운 캐스팅이이를 수행하는 올바른 방법이 아닙니다. 당신이해야 할 일은 원하는 작업을 유형 수행하고 기본 클래스에서 일반 메서드를 배치 한 다음 하위 클래스에서이를 오버라이드하는 것입니다. 예를 들어, GUIControl 자체를 그릴 수있게하려면 기본 클래스에 doDraw() 메서드를 넣고 각 하위 클래스에서 doDraw() 메서드를 재정 의하여 필요에 따라 재정의합니다. 하위 클래스에 getTitleBar(), getText() 등의 메소드를 추가 한 다음 호출자를 다운 캐스트하여 유형에 따라 해당 메소드를 호출하면 캡슐화가 중단됩니다.여러 하위 클래스가 드로잉을해야하는 공통 코드가있는 경우 다른 상위 클래스 또는 구성을 통해이를 제외시킵니다. dynamic_cast를 사용하거나 제네릭 서브 클래스에 특정 메서드를 넣는 것은 코드를 악화시킬 수 있습니다.

0

이 권한이있는 경우 : 기본 클래스 객체를 전달할 수 있지만 파생 클래스가 이러한 메소드를 구현하는 특정 파생 클래스 메소드를 호출 할 수있는 확실한 방법이 필요합니까?

은 도움이되는 '믹스 인'패턴처럼 소리 :

struct Base 
{ 
    virtual ~Base() {} 
}; 


struct Mixin 
{ 
    virtual ~Mixin() {} 
    virtual void mixedMethod() = 0; 
}; 

struct Concrete : Base, Mixin 
{ 
    virtual void mixedMethod() { std::cout << "Mixing" << std:: endl; } 
}; 

Base* create() { return new Concrete;} 

bool mixIt(Base& b) 
{ 
    Mixin* m = dynamic_cast<Mixin*>(&b); 
    if (m) 
     m->mixedMethod(); 
    return m; 
}  

void test() 
{ 
    Base* b = create(); 
    assert(mixIt(*b)); 
    Base base; 
    assert(!mixIt(base)); 
} 

[예, 실제 코드는 결코 polymorhic 클래스 구조체를 사용하지 않습니다; 단지 컴팩트하게 유지하는 것입니다.] 여기에있는 아이디어는 주어진 메소드의 가용성이 순수 추상 기본 클래스 인 Mixin 클래스에 캡슐화되어있을 가능성이 있으며 순수 가상 함수가 하나만있을 가능성이 있습니다. "know"를 원하면 기본 클래스 객체가 파생 된 유형이어야합니다. mixin 클래스 메소드를 호출 할 수 있습니다. 비회원 함수에서 테스트와 호출을 래핑 할 수 있습니다. 이렇게하면 기본 calss 인터페이스 자체를 깨끗하게 유지할 수 있습니다.

관련 문제