Effecticve学习笔记_条款45:运用成员函数模板接收所有兼容类型

  假设有一个基类和一个派生类像下面这样:

class Base
{};
class Derived : public Base
{};

  由于类间的上行转换时安全的,我们可以得到如下的正确结果:

Derived* d;
Base* b = static<Base*>d;

  下面我们自己写一个简单的SharedPtr智能指针类:

template<typename T>
class SharedPtr
{
private:
    T* ptr;
    static size_t count;
public:
    SharedPtr(T* _ptr) : ptr(_ptr), count(1) {}

    ~SharedPtr()
    {
        count--;
        if(count == 0)
        {
            delete ptr;
            ptr = NULL;
        }
    }
    SharedPtr(const SharedPtr<T>& other)
    {
        ptr = other.ptr;
        count++;
    }
};

  编译器在编译时不会通过SharedPtr< Base >pd(pb),因为在编译器替换T时,拷贝构造函数明确了接受类型必须是SharedPtr< Base >,而由SharedPtr< Derived >对象至SharedPtr< Base >对象的转换并不存在,所以编译器会报错。所以这里为了让所有类型都能够进行隐式转换,包括父类与子类间,我们需要将构造函数写成模板的形式,下面重新对上述代码进行了改进:

template<typename T>
class SharedPtr
{
private:
    T* _ptr;
    static int count;
public:
    template<typename U>
    SharedPtr(U* ptr)
    {
        _ptr = static_cast<T*>ptr;
        count = 1;
    }

    ~SharedPtr()
    {
        count--;
        if(count == 0)
        {
            delete _ptr;
            _ptr = NULL;
        }
    }

    T*  GetPointer() const
    {
        return _ptr;
    }

    template<typename U>
    SharedPtr(const SharedPtr<U>& other)
    {
        _ptr = static_cast<T*>(other.GetPointer());
        count++;
    }
};

  上述的构造函数声明为模板函数,参数为U,它可以与T相同,也可以不同,也就意味着它可以接受任何可以转化成T的类型了,比如父子类。这里还定义了GetPointer的方法,因为拷贝构建中传入的对象不一定是属于同一个类的,所以不能保证可以访问到类的私有成员。_ptr = static_cast < T * >(other.GetPointer())这句话其实就是转换的实质了,只要任何可以转成T* 的other* ,都是可以通过编译的,但如果是风马牛不相及的两个类,就不会通过编译。这里有一点要强调一下,我们可以把double转成int(窄化),也可以把int转成double(宽化),但注意double* 与int* 之间是不能相互转的,如果这样写int* a = (int*) (new double(2)),是不能通过编译的,可以用static_cast转换的类要有继承关系。

  总结:
  1. 请使用member function templates(成员函数模板)生成“可接受所有兼容类型”的函数;
  2. 如果你声明member templates用于“泛化copy构造”或“泛化assignment操作”,你还是需要声明正常的copy构造函数和copy assignment操作符。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值