2012-11-08 2 views
3

템플릿 매개 변수에 대해 다소 간단한 질문이 있습니다.상속 및 템플릿 매개 변수

list<PartitionT<CompareJobReady, CompareJobRunning> > partitions; 

PartitionT이 priority_queues을 사용하는 템플릿 클래스, 나는 비교 클래스를 사용하여 이러한 큐를 parametrise 할 : 나는 다음과 같은 목록을 사용하는 클래스 스케줄러를 쓰고 있어요. CompareJobReady와 CompareJobRunning은 theses 클래스입니다 (특정 연산자()를 구현합니다).

어쨌든 PartitionT는 템플릿 기반 클래스이므로 모든 유형의 비교기 클래스를 전달할 수 있기를 원합니다. 특히 CompareJobReadyEDFVD (CompareJobReady에서 상속)와 CompareJobRunningEDFVD (CompareJobRunning에서 상속)의 두 가지 추가 클래스를 정의했습니다. 실제로 지금 무엇을 원하는

, 다음처럼 작성할 수있게되고 :

list<PartitionT<CompareJobReady, CompareJobRunning> > *p = new list<PartitionT<CompareJobReadyEDFVD, CompareJobRunningEDFVD> >(); 

을하지만 컴파일러는 나에게 변환을 지시하는 것은 불가능합니다. 내 문제에 대한 최선의 해결책은 무엇입니까?

+1

표준 라이브러리의'std :: list'입니까? – dyp

+0

네, 말씀 드리지 않으면 미안합니다. – user1809140

답변

0

유형에 대해 템플릿을 사용하지만 동작에 대한 상속. 표준 라이브러리 자신의 그 요소의

list<PartitionT<CompareJobReady, CompareJobRunning> > *p = 
    new list<PartitionT<CompareJobReady, CompareJobRunning> >( 
    new CompareJobReadyEDFVD(), new CompareJobRunningEDFVD()); 
+0

이것이 표준 목록 인 경우'list'의 ctor가 올바르지 않습니다. [initializer-list] (http://en.cppreference.com/w/cpp/container/list/list) (7)를 사용할 수 있습니다. – dyp

+0

클래스의 인스턴스가 아니라 priority_queue에 클래스 자체를 전달해야하기 때문에 이것이 내 문제를 해결하는지 확신 할 수 없습니다. – user1809140

+0

하지만 비교기는 전체 클래스 ** 별도의 ** 클래스 템플릿 매개 변수 인'std :: priority_queue'. 'PartitionT' 템플릿 클래스 내에서 사용합니까? 그렇지 않다면 그냥 제거하십시오. –

1

컨테이너 클래스처럼, 당신은 (템플릿 인수의 형태 등) 구축 비교기 클래스를 통과 할 수있는에 생성자를 제공합니다. 당신이있는 경우 즉, :

class Base {}; 
class Child : public Base {}; 

std::list <Base> myList; 
std::list <Base> *pMyList; 

그런 다음 myList의 요소 만 (참조) 타입 Base의 객체로 액세스 할 수 있습니다. Base 유형의 요소 (예 : push_back, emplace_back)를 저장하고 참조/사본 (예 : front 또는 반복자를 통해)을 가져올 수 있습니다 (예 : cppreference/list 참조). 이제 push_back에서 살펴 보자 : value_type 당신이 std::list에 전달 된 첫 번째 템플릿 매개 변수가

void push_back(const value_type&); 

. 귀하의 경우는 PartitionT < CompareJobReady, CompareJobRunning >이고, 위 예의 경우 Base입니다. push_back 실제로 복사본 복사본을 전달하고 그 복사본을 새 요소로 복사합니다. 왜 그런가요? 새 요소는 목록에서 소유 할 수 있기 때문입니다. 목록 자체가 파괴되면 목록은이 요소를 파괴 할 수 있으며 두 목록을 이동/교환하면 다른 목록으로 전달할 수 있습니다. 요소가 복사되지 않고 외부에서 소멸 된 경우 목록에 파괴 된 요소가 포함됩니다. 목록에서 제공하는 보증이 깨집니다 (매우 좋지는 않을 것입니다).

또 다른 예 (단순하지만 매우 정확하지는 않음) : list은 할당자를 통해 요소에 메모리를 할당합니다. 기본 할당자는 std::allocator<Base>입니다. Base 유형의 객체를 저장하는 데 필요한만큼 요소의 메모리 만 할당합니다.

당신이 pMyList = new std::list <Child>; 같은 "std::list<Base> 포인터"왼쪽이 유형 인 반면, "std::list<Child> 포인터의"에서 오른쪽 결과를 할

. std::list<Base> std::list<Child>에서 상속되지 않거나 변환을 정의하지 않으므로이 두 유형은 관련이 없습니다.이것이 왜 좋은지에 대한 몇 가지 이유가 있습니다. 하나는 범용 프로그래밍이 어떤 유형을 다루어야 하는지를 요구한다는 것입니다. 다형성 (Polymorphism)은 추상화이므로 컴파일 타임에 처리 할 유형을 알 필요도 없습니다.

C++의 다형성은 포인터 또는 참조를 통해 작동합니다. 이 유형의 불가지론 목록의 일부 Child 객체 (예 : 그것은 단지 Base 유형을 알고) 준비하려는 경우 그래서, 당신은 포인터로 저장해야합니다 :

std::list < std::shared_ptr<Base> > myList2; 

myList2.push_back(new Child); // better not use, there's a caveat (1) 

// approach w/o this caveat 
std::shared_ptr<Base> pNewChild(new Child); // or make_shared 
myList2.push_back(pNewChild); 

주 나는 여기에 shared_ptr를 사용, 즉 더 나은 목적에 맞는 경우뿐만 아니라 unique_ptr를 사용할 수 있지만 원시 ptrs를 사용해서는 안 :이 myList2shared_ptr 요소를 소유하고 shared_ptr 공유 소유권 (유형 자료의) 객체를 보유하고, myList2 간접적으로 Child를 소유 목록에있는 ptrs를 저장하는 객체. 원시 ptrs는 소유권을 나타내지 않으므로 예를 들어 누구를 파기해야할지 분명하지 않습니다. "Rule of Zero"에 대해 더 자세히 읽어보십시오.

(1)이 예에는 영향을 미치지 않지만주의 사항이 있습니다 (boost 참조). 당신이 정말로 어딘가에 비교 자 클래스를 선택하여 제네릭 프로그래밍을 수행 할 경우


, 당신은 "컴파일 시간에 충실해야한다"귀하의 목록에있는 유형 (*p의 유형) list<Base> 아니라 일반적인 고정되어서는 안된다 (템플리트 사용) 및 사용하는 모든 알고리즘은 generic이어야합니다. 일반 프로그래밍은 컴파일 타임에 코드를 만드는 것이므로 일반 프로그래밍과 유형의 런타임 선택을 혼합 할 수는 없습니다 (간단히 *).

* RTTI를 남용하여 매우 느려지는 해킹이 있습니다.