所谓智能指针是行为像指针的对象,并提供指针没有的机能。真实的指针支持隐式转换,也就是派生类指针能转换成基类指针
class Base
{
public:
Base(){};
~Base(){};
private:
int b;
};
class Derived:public Base
{
public:
Derived(){};
~Derived(){};
private:
int d;
};
int main()
{
Base* pb = new Derived;//将派生类指针转换成基类指针
return 0;
}
指向non_const对象的指针可以转换为 指向const对象的指针
int main()
{
int a = 1;
int *pa = &a;
const int* pb= pa;
return 0;
}
但是对于智能指针
template<typename T>
class SmartPtr{
public:
explicit SmartPtr(T* realPtr)
{
count = 1;
ptr = realPtr;
}
~SmartPtr()
{
if (--count == 0)
{
delete ptr;
ptr = NULL;
}
}
SmartPtr(const SmartPtr<T>& smartptr)
{
ptr = smart.ptr;
++count;
}
private:
T* ptr;
static size_t count;
};
int main()
{
SmartPtr<Base> b_ptr = SmartPtr<Derived> (new Derived);
return 0;
}
SmartPtr<Base> b_ptr = SmartPtr<Derived> (new Derived);这种转化是不合法的,error C2440: “初始化”: 无法从“SmartPtr<Derived>”转换为“SmartPtr<Base>”
这是因为两个SmartPtr是同一个template的不同具现体,他们之间没有什么关系。若想实现上述转变可以设法编写构造函数实现上述转换,但由于转换很多,不可能写出每一种构造函数,所以可以将构造函数写成成员函数模板
给上述智能指针的模板添加函数:template<typename U>
SmartPtr(SmartPtr<U>& other);
该函数意味着对于任何T和任何U,可以根据SmartPtr<U>生成SmartPtr<T>,称之为泛化构造函数。之所以没有再函数前加explicit是为了效法真实指针类型之间的隐式转换。
该泛化构造函数还需要满足不允许基类指针向派生类转等行为,所以需要添加约束条件
template<typename U>
SmartPtr(SmartPtr<U>& other) :ptr(other.getptr)
{
}
T* get() const{ return ptr; }
{
};
上述变化是通过成员初值列,用U*指针作为初值初始化T*指针,这就要求存在U*到T*的隐式转换,正好满足真实指针的行为。该泛化的构造函数只有在实参隶属于兼容类型时才通过编译。
请记住:
1.请使用member function templates(成员函数模板)生成“可接受所有兼容类型”的函数
2.如果你声明member templates用于“泛化copy构造”或“泛化assignment操作”(此时编译器还是会生成默认的,如果没有自己写正常的),你还是需要声明正常的copy构造函数和copy assignment操作符。