设为首页 加入收藏

TOP

Item 45:使用成员函数模板来接受所有兼容的类型
2016-02-23 11:35:08 】 浏览:9610
Tags:Item 使用 成员 函数 模板 接受 所有 兼容 类型

Item 45: Use member function templates to accept “all compatible types”.

Item 13提到智能指针可用来自动释放堆中的内存,STL中的迭代器也是一种智能指针,它甚至支持链表元素指针的++操作。 这些高级特性是普通指针所没有的。本文以智能指针为例,介绍成员函数模板的使用:

  • 成员函数模板可以使得函数可以接受所有兼容的类型。
  • 如果你用成员函数模板声明了拷贝构造函数和赋值运算符,仍然需要手动编写普通拷贝构造函数和拷贝运算符。

    隐式类型转换

    智能指针虽然比普通指针提供了更多有用的特性,但也存在一些问题,比如我们有一个类的层级:

    class Top{};
    class Middle: public Top{};
    class Bottom: public Middle{};
    

    普通指针可以做到派生类指针隐式转换为基类指针:

    Top *p1 = new Bottom;
    const Top *p2 = p1;
    

    但如果是智能指针,比如我们实现了SmartPtr,我们则需要让下面代码经过编译:

    SmartPtr
         
           p1 = SmartPtr
          
           (new Bottom); SmartPtr
           
             p2 = p1; 
           
          
         

    同一模板的不同实例之间是没有继承关系的,在编译器看来AutoPtr AutoPtr 是完全不同的两个类。 所以上述代码直接编译是有问题的。

    重载构造函数

    为了支持用SmartPtr 初始化SmartPtr ,我们需要重载SmartPtr的构造函数。 原则上讲,有多少类的层级我们就需要写多少个重载函数。因为类的层级是会扩展的,因此需要重载的函数数目是无穷的。 这时便可以引入成员函数模板了:

    template
         
           class SmartPtr{ public: template
          
            SmartPtr(const SmartPtr& other); }; 
          
         

    注意该构造函数没有声明为explicit,是为了与普通指针拥有同样的使用风格。子类的普通指针可以通过隐式类型转换变成基类指针。

    接受同一模板的其他实例的构造函数被称为通用构造函数(generalized copy constructor)。

    兼容类型检查

    事实上,通用构造函数提供了更多的功能。他可以把一个SmartPtr 隐式转换为SmartPtr ,把一个SmartPtr 转换为SmartPtr 。 但普通指针是不允许这些隐式转换的。因此我们需要把它们禁用掉。注意一下通用构造函数的实现方式便可以解决这个问题:

    template
         
           class SmartPtr{ public: template
          
            SmartPtr(const SmartPtr& other): ptr(other.get()){}; T* get() const{ return ptr; } private: T *ptr; }; 
          
         

    ptr(other.get())时编译器会进行类型的兼容性检查,只有当U可以隐式转换为T时,SmartPtr才可以隐式转换为SmartPtr 。 这样就避免了不兼容指针的隐式转换。

    其他使用方式

    除了隐式类型转换,成员函数模板还有别的用途,例如赋值运算符。。下面是shared_ptr的部分源码

    template
         
           class shared_ptr{ public: template
          
            explicit shared_ptr(Y *p); template
           
             shared_ptr
            
              const& r>; template
             
               shared_ptr& operator=(shared_ptr
              
                const& r); }; 
              
             
            
           
          
         

    可以看到普通指针Y*shared_ptr 声明了explicit,需要显式的类型转换;而shared_ptr 之间只需要隐式转换。 使用拷贝构造函数模板存在一个问题:编译器是会生成默认的拷贝构造函数?还是会从你的模板实例化一个拷贝构造函数? 即Y == T场景下的编译器行为。

    事实上,成员函数模板不会改变C++的规则。C++规则讲:如果你没有声明拷贝构造函数,那么编译器应该生成一个。 所以Y == T时拷贝构造函数不会从成员函数模板实例化,而是会自己生成一个。

    所以shared_ptr模板中还是手动声明了拷贝构造函数:

    template
         
           class shared_ptr{ public: shared_ptr(shared_ptr const& r); template
          
            shared_ptr(shared_ptr
           
             const& r); shared_ptr& operator=(shared_ptr const& r); template
            
              shared_ptr& operator=(shared_ptr
             
               const& r); };
             
            
           
          
         
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Item 49:new handler的行为 下一篇HDU 3068 最长回文(Manacher)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目