Effective C++ 条款45

本节条款的题目是运用成员模板接受所有兼容类型

作者阐述自己的观点是通过智能指针的例子。

在学习本节条款之前我们要先明白关于隐式转化的问题

如下代码:

#include<iostream>
using namespace std;
class A
{
public:
    explicit A(int i):a(i){};
    A(const A&obj):a(obj.a)
    {
    }
private:
    int a;
};

int main()
{
    int value =0;
    A a = value;//编译不通过,因为构造函数中有explicit限定符
    return 0; 

}

我们知道因为explicit限定符的存在编译不通过。

下面我们看另一段书上的代码:

template<typename T>
    class SmartPrt{
    public:
        explicit SmartPtr(T* realPtr);
        ……
    };
    SmartPtr<Top> pt1=SmartPtr<Middle>(new Middle);
    SmartPrt<Top> pt2=SmartPrt<Bottom>(new Bottom);
    SmartPrt<const Top> pct2=pt1;
我们可以知道,因为`SmartPtr<Top>`类型和`SmartPtr<Middle>`

类型不同,再加上explicit SmartPtr<Middle>中的explicit限定符,SmartPtr<Top> pt1=SmartPtr<Middle>(new Middle);这句代码编译不通过。

而且编译器并不认为SmartPtr<Top>类型和SmartPtr<Middle>类型存在继承关系。

为了能够实现相互转化,可以添加本节的主旨技术去解决上面出现的问题。

如下代码:

 template<typaname T>
    class SmartPtr{
    public:
        template<typename U>
        SmartPrt(const SmartPrt<U>& other)
        :heldPrt(other.get()){};
        T* get() const{return heldPrt;}
        ……
    private:
        T* heldPrt;
    };

    SmartPtr<Top> pt1=SmartPtr<Middle>(new Middle);
    SmartPrt<Top> pt2=SmartPrt<Bottom>(new Bottom);
    SmartPrt<const Top> pct2=pt1;

我们添加了一个member function template函数,因为typename T和typename U 是两种类型,并且构造函数中没有explicit关键字,不会阻止heldPrt(other.get())的隐式转换。所以,以上代码可以通过编译。

作者最后列出了TR1规范中关于tr1::shared_ptr的一份摘录

如下:

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

我们可以发现上面只有泛化copy构造函数不是explicit,表示shared_ptr 的隐式转化被允许,而其他的智能指针转化不被允许。

这里还有一个需要注意的地方,在class类声明泛化copy构造函数(member template),并不会阻止编译器生成它们自己的copy构造函数(non-template),换言之,如果程序中只写了泛化的copy构造函数,那么编译器还是会自动生成一个非泛化的版本出来,如果不想要这个缺省版本,那一定不能偷懒,要两个版本的copy构造函数都要写。

代码如下:

template<typaname T>
    class SmartPtr{
    public:
        template<typename U>
        SmartPrt(const SmartPrt<U>& other)
        :heldPrt(other.get()){};
        SmartPtr(){}//如果不写自己的非泛化构造函数,编译器会自动生成自己的默认非泛化构造函数。
        T* get() const{return heldPrt;}
        ……
    private:
        T* heldPrt;
    };

最后:

作者总结如下:

1. 请使用member function templates(成员函数模板)生成“可接受所有兼容类型”的函数;

2. 如果你声明member templates用于“泛化copy构造”或“泛化assignment操作”,你还是需要声明正常的copy构造函数和copy assignment操作符。

时间: 2024-10-15 10:38:59

Effective C++ 条款45的相关文章

Effective C++条款45 附加代码

本节是对上一篇博客的附加代码,基本的45条款思想已经实现. #include<iostream> using namespace std; template<typename T> class SharedPtr { public: template<typename U> SharedPtr(const SharedPtr<U>&u) :ptr(u.get()) { count++; } SharedPtr(T*ptr_):ptr(ptr_){}

Effective C++ 条款45 运用成员函数模板接受所有兼容类型

1. "智能指针"是行为像指针的对象,但它们能提供指针没有的功能:shared_ptr,weak_ptr,auto_ptr(见条款13)实现对堆内存的自动管理,STL的迭代器实现对整个容器的遍历等. 真正的指针的优势在于支持继承层次中派生类指针向基类指针的转换(当然标准库shared_ptr,weak_ptr,auto_ptr等已实现). 2. 由于同一template的不同具现体之间没有直接联系,也就是说对于自定义的智能指针(假设名为SmartPtr),如果不额外采取手段支持基层层次

More Effective C++ 条款35 让自己习惯于标准C++ 语言

(由于本书出版于1996年,因此当时的新特性现在来说可能已经习以为常,但现在重新了解反而会起到了解C++变迁的作用) 1. 1990年后C++的重要改变 1). 增加了新的语言特性:RTTI,namespaces,bool,关键词mutable和explicit,enums作为重载函数之自变量所引发的类型晋升转换,以及"在class 定义区内直接为整数型(intergral) const static class members设定初值"的能力. 2). 扩充了Templates的特性

effective c++ 条款4 make sure that objects are initialized before they are used

1 c++ 类的数据成员的初始化发生在构造函数前 class InitialData { public: int data1; int data2; InitialData(int a, int b) { data1 = a: //this is assignment data2 = b; //this is assignment } /* InitialData(int a, int b):data1(a),data2(b) //this is initial {} */ } 2 不同cpp文

More Effective C++ 条款34 如何在一个程序中结合C++和C

1. C++和C混合使用的前提之一就是编译器产生兼容的目标文件(.lib和.dll等).所谓"兼容",指的是编译器在"预编译器相依的特性上"一致,如int和double大小,参数压栈机制等,只有在这个基础上才能讨论结合使用C++和C模块的问题. 2. 在1的基础上,要结合使用C++和C的模块,主要有以下几点需要注意: 1). name mangling(名称重整) Name mangling是C++用于支持函数重载的机制,它对重载的函数名称进行一定改变,使得每个函数

Effective C++ 条款3 尽可能用const

1. const可被施加于任何作用域内的对象,函数参数,函数返回类型,成员函数本体.用const修饰指针,如果const出现在*之前,表明指针不能更改所指向的对象的内容,如果const出现在*之后,表明指针只能指向同一块内存.另外int const*p和const int*p含义相同.如果对象成员有普通指针,那么构造该类的一个const对象时,const修饰使得该指针只能指向同一块内存,但指针指向的内容可以改变. 2. 将某些东西声明为const可以帮助编译器侦测出错误用法. 3. 编译器强制实

effective c++ 条款13 use object to manage resources.

请求的系统资源需要最终还回系统,为了避免遗忘返还这个动作,可以利用析构函数在object销毁时自动调用的特点来实现. 简单说就是用object来管理资源. 以内存资源为例 class Investment {}; Investment* creatInvestment(){...} // factory function to produce investment object void main() { Investment* pInv = creatInvestment();//call t

effective c++ 条款3 use const whereever you can

1 const 传达的意思应该是这个变量是常量不能更改 2 const 在 * 左边表示数据是const,在右边表示指针是const // char greeting[] = "hello"; char* p = greeting; //const *: const data //* const: const pointer char const *p1 = greeting; // const data char * const p2 = greeting; // const poi

effective c++ 条款18 make interface easy to use correctly and hard to use incorrectly

举一个容易犯错的例子 class Date { private: int month; int day; int year; public: Date(int month,int day,int year) { this->month = month; ... } } //wrong example Date date(30,3,1995);//should be 3,30 Date date(2,30,1995);//should be 3,30 使用类型可避免这个问题 class Month