문제
나는 이것이 전에 요청 된 것 같은 느낌이 들지만, 그것을 찾을 수 없으며, Google에서 유용한 것을 찾을 수 없다. 어쩌면 "공분산"은 내가 찾고있는 단어가 아니지만이 개념은 기능의 공분산 반환 유형과 매우 유사하므로 아마도 맞다고 생각합니다. 다음은 내가하고 싶은 일이며 컴파일러 오류를 제공합니다.
class Base;
class Derived : public Base;
SmartPtr<Derived> d = new Derived;
SmartPtr<Base> b = d; // compiler error
그 수업이 완전히 살아 났다고 가정합니다 ... 나는 당신이 아이디어를 얻는다고 생각합니다. 변환 할 수 없습니다 SmartPtr<Derived>
a SmartPtr<Base>
불분명 한 이유 때문에. 나는 이것이 C ++와 다른 많은 언어에서 정상이라는 것을 기억하지만, 현재 나는 이유를 기억할 수 없다.
내 루트 질문은 :이 과제 작업을 수행하는 가장 좋은 방법은 무엇입니까? 현재 포인터를 꺼내고 있습니다 SmartPtr
, 기본 유형으로 명시 적으로 업 캐스트 한 다음 새로 포장 SmartPtr
적절한 유형 중 SmartPtr
클래스는 침입 참조 계수를 사용합니다). 길고 지저분합니다. 특히 내가 마무리해야 할 때 SmartPtr
또 다른 물체에서 ... 어떤 지름길이 있습니까?
해결책
카피 생성자와 할당 연산자는 모두 다른 유형의 SmartPtr을 가져 와서 포인터를 서로 복사하려고 시도해야합니다. 유형이 호환되지 않으면 컴파일러가 불만을 제기하고 호환되는 경우 문제를 해결했습니다. 이 같은:
template<class Type> class SmartPtr
{
....
template<class OtherType> SmartPtr(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> copy constructor
template<class OtherType> SmartPtr<Type> &operator=(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> assignment operator
};
다른 팁
SmartPtr<Base>
그리고 SmartPtr<Derived>
두 가지 뚜렷한 인스턴스화입니다 SmartPtr
주형. 이 새로운 클래스는 그 상속을 공유하지 않습니다 Base
그리고 Derived
하다. 따라서, 당신의 문제.
이 과제 작업을 수행하는 가장 좋은 방법은 무엇입니까?
SmartPtr<Base> b = d;
과제 연산자를 호출하지 않습니다. 이것은 카피 -CTOR를 호출하며 (대부분의 경우 사본은 피해를 입히고) 다음과 같습니다.
SmartPtr<Base> b(d);
a SmartPtr<OtherType>
그리고 그것을 구현하십시오. 과제 연산자도 마찬가지입니다. SmartPtr의 의미론을 염두에두고 Copy-CTOR 및 OP = OP =를 작성해야합니다.
템플릿은 공분산이 아니며, 좋습니다. 다음 경우 어떤 일이 일어날 지 상상해보십시오.
vector<Apple*> va;
va.push_back(new Apple);
// Now, if templates were covariants, a vector<Apple*> could be
// cast to a vector<Fruit*>
vector<Fruit*> & vf = va;
vf.push_back(new Orange); // Bam, we just added an Orange among the Apples!
당신이하려는 일을 달성하기 위해서는 SmartPointer 클래스에는 다른 SmartPointer 또는 다른 유형의 포인터를 사용하는 템플릿 생성자가 있어야합니다. 당신은 boost :: shared_ptr을 볼 수 있습니다.
template <typename T>
class SmartPointer {
T * ptr;
public:
SmartPointer(T * p) : ptr(p) {}
SmartPointer(const SmartPointer & sp) : ptr(sp.ptr) {}
template <typename U>
SmartPointer(U * p) : ptr(p) {}
template <typename U>
SmartPointer(const SmartPointer<U> & sp) : ptr(sp.ptr) {}
// Do the same for operator= (even though it's not used in your example)
};
에 달려 있습니다 SmartPtr
수업. 복사 생성자 (또는 귀하의 경우 할당 연산자)가있는 경우 SmartPtr<T>
, 여기서 t는 구성된 유형 인 경우 작동하지 않을 것입니다. SmartPtr<T1>
관련이 없습니다 SmartPtr<T2>
T1과 T2가 상속과 관련이 있더라도.
그러나 SmartPTR이있는 경우 템플릿 템플릿 매개 변수와 함께 생성자/할당 연산자를 복사하십시오 TOther
, 그것은 받아들입니다 SmartPtr<TOther>
, 그런 다음 작동해야합니다.
SmartPTR 클래스를 제어한다고 가정하면 솔루션은 템플릿 생성자를 제공하는 것입니다.
template <class T>
class SmartPtr
{
T *ptr;
public:
// Note that this IS NOT a copy constructor, just another constructor that takes
// a similar looking class.
template <class O>
SmartPtr(const SmartPtr<O> &src)
{
ptr = src.GetPtr();
}
// And likewise with assignment operator.
};
T 유형과 O 유형이 호환되면 작동하지 않으면 컴파일 오류가 발생합니다.
가장 쉬운 것은 다음에 따라 다른 smartptr로 자동 변환을 제공하는 것입니다.
template <class T>
class SmartPtr
{
public:
SmartPtr(T *ptr) { t = ptr; }
operator T * () const { return t; }
template <class Q> operator SmartPtr<Q> () const
{ return SmartPtr<Q>(static_cast<Q *>(static_cast<T *>(* this))); }
private:
T *t;
};
이 구현은 변환 연산자 템플릿이 스마트 포인터의 의미론에 대해 알 필요가 없다는 점에서 강력하므로 참조 계산 등을 복제 할 필요가 없습니다.