문제

C ++에 대한 근본적인 오해가있는 것 같습니다.

나는 다형성 용기 솔루션을 좋아합니다. 감사합니다. 제 관심을 가져 주셔서 감사합니다. :)


따라서 비교적 일반적인 컨테이너 유형 객체를 만들 필요가 있습니다. 또한 일부 비즈니스 관련 논리를 캡슐화합니다. 그러나 기본 데이터 유형에서 복잡한 클래스에 이르기까지 모든 컨테이너에 본질적으로 임의의 데이터를 저장해야합니다.

따라서 즉시 템플릿 클래스의 아이디어로 점프하여 완료됩니다. 그러나 나는 C ++ 다형성과 템플릿이 함께 잘 작동하지 않는다는 것을 알았습니다. 우리가 일해야 할 복잡한 논리가 있기 때문에, 나는 템플릿이나 다형성을 고수하고 둘 다를 만들어 C ++와 싸우려고하지 않을 것입니다.

마지막으로, 내가 하나 또는 다른 것을하고 싶다는 것을 감안할 때, 나는 다형성을 선호합니다. "이 컨테이너에는 비슷한 유형이 포함되어 있습니다"와 같은 제약 조건을 나타내는 것이 훨씬 쉽다는 것을 알게됩니다.

질문의 주제로 가져 오기 : 가장 추상적으로, 나는 "푸시 (void* data) 및 팝 (void* data)과 비슷한"컨테이너 "순수한 가상 인터페이스를 가질 수 있다고 생각합니다 (레코드 용. , 나는 실제로 스택을 구현하려고하지 않습니다).

그러나 나는 최상위 수준에서 Void*를 실제로 좋아하지 않으며, 콘크리트 컨테이너가 사용할 수있는 데이터 유형에 제약 조건을 추가 할 때마다 서명이 변경 될 것이라고는 말할 것도 없습니다.

요약 : 요소를 검색하는 다양한 방법이있는 비교적 복잡한 용기가 있습니다. 컨테이너로 들어갈 수있는 요소에 대한 제약 조건을 변화시킬 수 있기를 원합니다. 요소는 여러 종류의 컨테이너와 함께 작동해야합니다 (특정 컨테이너의 제약 조건을 충족하는 한).

편집 : 또한 용기 자체가 다형성이어야한다고 언급해야합니다. 그것이 템플릿 C ++를 사용하고 싶지 않은 주된 이유입니다.

그래서 - Java 유형 인터페이스에 대한 사랑을 떨어 뜨리고 템플릿으로 가야합니까? void*를 사용하고 모든 것을 정적으로 캐스팅해야합니까? 아니면 아무것도 선언하지 않는 빈 클래스 정의 "요소"로 가야하고 "요소"계층 구조에서 최상위 클래스로 사용해야합니까?

내가 스택 오버플로를 좋아하는 이유 중 하나는 많은 응답이 내가 고려하지 않은 다른 접근법에 대한 흥미로운 통찰력을 제공하기 때문입니다. 통찰력과 의견에 미리 감사드립니다.

도움이 되었습니까?

해결책

요소가 포함 된 루트 컨테이너 클래스가 없을 수 있습니까?

template <typename T>
class Container
{
public: 

   // You'll likely want to use shared_ptr<T> instead.
   virtual void push(T *element) = 0;
   virtual T *pop() = 0;
   virtual void InvokeSomeMethodOnAllItems() = 0;
};

template <typename T>
class List : public Container<T>
{
    iterator begin();
    iterator end();
public:
    virtual void push(T *element) {...}
    virtual T* pop() { ... }
    virtual void InvokeSomeMethodOnAllItems() 
    {
       for(iterator currItem = begin(); currItem != end(); ++currItem)
       {
           T* item = *currItem;
           item->SomeMethod();
       }
    }
};

그런 다음이 컨테이너는 다형적으로 전달 될 수 있습니다.

class Item
{
public:
   virtual void SomeMethod() = 0;
};

class ConcreteItem
{
public:
    virtual void SomeMethod() 
    {
        // Do something
    }
};  

void AddItemToContainer(Container<Item> &container, Item *item)
{
   container.push(item);
}

...

List<Item> listInstance;
AddItemToContainer(listInstance, new ConcreteItem());
listInstance.InvokeSomeMethodOnAllItems();

이렇게하면 컨테이너 인터페이스를 유형 안전 일반적인 방식으로 제공합니다.

포함 할 수있는 요소 유형에 제약 조건을 추가하려면 다음과 같은 작업을 수행 할 수 있습니다.

class Item
{
public:
  virtual void SomeMethod() = 0;
  typedef int CanBeContainedInList;
};

template <typename T>
class List : public Container<T>
{
   typedef typename T::CanBeContainedInList ListGuard;
   // ... as before
};

다른 팁

표준 컨테이너를 사용하여 볼 수 있습니다 부스트 :: 누구 진정으로 임의의 데이터를 컨테이너에 저장하는 경우.

당신이 오히려 부스트 :: ptr_container 그게 어디에 ~할 수 있다 컨테이너에 저장되어 일부 기본 유형에서 파생되어야하며 컨테이너 자체는 기본 유형 만 참조 할 수 있습니다.

간단한 것은 Container, 당신이 저장하려는 각 종류의 품목에 대해 서브 클래스. 그런 다음 표준 컬렉션 클래스를 사용할 수 있습니다 (std::vector, std::list, 포인터를 저장하는 등 Container. 포인터를 저장하기 때문에 할당/거래를 처리해야합니다.

그러나 이러한 유형이 매우 다른 유형의 개체를 저장하기 위해 단일 컬렉션이 필요하다는 사실은 응용 프로그램 설계에 무언가 잘못 될 수 있음을 나타냅니다. 이 슈퍼 게레네릭 컨테이너를 구현하기 전에 비즈니스 로직을 다시 방문하는 것이 좋습니다.

다형성과 템플릿은 올바르게 사용하면 함께 잘 작동합니다.

어쨌든, 나는 당신이 각 컨테이너 인스턴스에 한 가지 유형의 객체 만 저장하고 싶다는 것을 이해합니다. 그렇다면 템플릿을 사용하십시오. 이렇게하면 잘못된 객체 유형을 실수로 저장하지 못하게됩니다.

컨테이너 인터페이스의 경우 : 디자인에 따라 템플릿으로 만들 수 있고 다음과 같은 방법을 가질 수 있습니다. void push(T* new_element). 컨테이너 (알 수없는 유형)에 컨테이너에 추가하려고 할 때 객체에 대해 알 수있는 것을 생각해보십시오. 처음에는 물체가 어디에서 나올까요? 반환하는 함수 void*? 비교할 수 있다는 것을 알고 있습니까? 적어도 저장된 객체 클래스가 코드에 정의되면 공통 조상으로부터 모두 상속 될 수 있습니다. Storable, 및 사용 Storable* 대신에 void*.

이제 객체가 항상 다음과 같은 방법으로 컨테이너에 추가됩니다. void push(Storable* new_element), 그런 다음 컨테이너를 템플릿으로 만드는 데 부가 가치가 없습니다. 그러나 당신은 그것이 저장소를 저장해야한다는 것을 알게 될 것입니다.

첫째, 템플릿과 다형성은 직교 개념이며 함께 잘 작동합니다. 다음으로 특정 데이터 구조를 원하는 이유는 무엇입니까? STL 또는 부스트 데이터 구조는 어떻습니까 (특히 포인터 컨덕터) 당신을 위해 작동하지 않습니다.

귀하의 질문이 주어지면 상황에서 상속을 오용하는 것 같습니다. 만들 수 있습니다 "제약"컨테이너에 들어가는 것에 대해, 특히 템플릿을 사용하는 경우. 이러한 제약 조건은 컴파일러와 링커가 제공 할 수있는 것 이상으로 갈 수 있습니다. 실제로 상속 및 오류가있는 이런 종류의 일에 더 어색합니다.

다형성을 사용하여 기본적으로 컨테이너의 기본 클래스와 데이터 유형에 대한 도출 클래스가 남아 있습니다. 기본 클래스/파생 클래스는 양방향으로 필요한만큼의 가상 기능을 가질 수 있습니다.

물론 이것은 기본 데이터 유형을 파생 클래스에 랩핑해야한다는 것을 의미합니다. 전반적으로 템플릿 사용을 재고하면 템플릿을 사용하는 곳입니다. 템플릿 인베이스에서 파생 된 클래스를 만들고 원시 데이터 유형 (및 템플릿에서 제공하는 것보다 더 많은 기능이 필요하지 않은 경우)을 사용하십시오.

각 템플릿 유형에 대해 Typedefs가 인생을 더 쉽게 만들 수 있다는 것을 잊지 마십시오. 특히 나중에 나중에 그 중 하나를 수업으로 바꿔야한다면

당신은 또한 체크 아웃하고 싶을 수도 있습니다 부스트 컨셉 체크 라이브러리 (BCCL) 이 경우 템플릿 클래스의 템플릿 매개 변수에 제약 조건을 제공하도록 설계되었습니다.

그리고 다른 사람들이 말한 것을 반복하기 위해, 나는 다형성과 템플릿을 혼합하는 데 문제가 없었으며, 그들과 상당히 복잡한 일을했습니다.

Java와 같은 인터페이스를 포기하고 템플릿을 사용할 필요가 없습니다. 조쉬의 제안 일반적인베이스 템플릿 컨테이너는 분명히 다형성 통과 용기와 어린이를 수행 할 수 있지만, 또한 포함 된 항목이기 위해 추상 클래스로 인터페이스를 구현할 수 있습니다. 당신이 제안한대로 추상적 인 iCompayable 클래스를 만들 수 없었기 때문에 다음과 같이 다형성 기능을 가질 수있는 이유는 없습니다.

class Whatever
{
   void MyPolymorphicMethod(Container<IComparable*> &listOfComparables);
}

이 방법은 이제 icomparable을 구현하는 클래스를 포함하는 컨테이너의 자식을 가져갈 수 있으므로 매우 유연합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top