반면 일반 포인터도 스마트 포인터로 대신할 수 없는 특징이 있다. 그 중 하나가 암시적 변환(implicit conversion)을 지원 한다는 점이다. 파생 클래스는 기본 클래스로 변환되고, 비상수 객체에서 상수 객체로의 암시적 변환이 가능하다. 스마트 포인터는 이것이 안된다.
그럼 어떻게 방법이 없을까 ? 멤버 함수 템플릿(member function template)를 사용하면 된다. 바로 생성자를 만들어내는 템플릿을 사용하는 것이다.
template<typename T> class SmartPtr { public: template<typename U> SmartPtr(const SmartPtr<U>& other) : heldPtr(other.get()) { ... } T* get() const { return heldPtr; } private: T* heldPtr; };
이런 꼴이 같은 템플릿을 써서 인스턴스화 되지만 타입이 다른 타입의 객체로 부터 원하는 객체를 만들어주는 것을 일반화 복사 생성자(generalized copy constructor)라고 부른다. 그렇다고 해서 기본 클래스로부터 자식 클래스로 변환하거나 int* 를 double* 로 변환하는 등의 원래부터 안되는 것을 되게 해주지는 못한다. 못하게 하는것이 세상의 이치에도 맞는 것이고.
멤버 함수 템플릿은 복사생성자 뿐 아니라 대입 연산에도 많이 쓰인다.
* 호환되는 모든 타입을 받아들이는 멤버 함수를 만들려면 멤버 함수 템플릿을 사용합시다.
* 일반화된 복사 생성 연산과 일반화된 대입 연산을 위해 멤버 템플릿을 선언했다 하더라도, 보통의 복사 생성자와 복사 대입 연산자는 여전히 직접 선언해야 합니다.
댓글 없음:
댓글 쓰기