45:运用成员函数模板接受所有兼容类型

news/2024/11/25 0:26:24/

所谓智能指针是“行为像指针”的对象,并提供指针没有的机能。STL容器的迭代器几乎总是智能指针,无疑地,你不会奢望使用"++"将一个内置指针从linked list的某个节点移到另一个节点,但这在list::itertor身上办得到。

真实指针做得很好的一件事是,支持隐式转换。Derived class指针可以隐式转换为base class指针,“指向non-const对象”的指针可以转换为“指向const对象”······等等。

下面是可能发生于三层继承体系的一些转换:

class Top{/*..*/ };
class Middle:public Top{/*...*/ };
class Bottom:public Middle{/*...*/ };
Top* pt1 = new Middle;//将Middle*转换为Top*
Top* pt2 = new Bottom;//将Bottom*转换为Top*
const Top* pct2 = pt1;//将Top*转换为const Top*

但若想在用户自定的智能指针中模拟上述转换,稍稍有点麻烦。

我们希望以下代码通过编译:

template <typename T>
class SmartPtr {
public://智能指针通常以内置指针完成初始化explicit SmartPtr(T* realPtr);//...
};
//将SmartPtr<Middle>转换为SmartPtr<Top>
SmartPtr<Top> pt1 = SmartPtr<Middle>(new Middle);
//将SmartPtr<Bottom>转换为SmartPtr<Top>
SmartPtr<Top> pt2 = SmartPtr<Bottom>(new Bottom);
//将SmartPtr<Top>转换为SmartPtr<const Top>
SmartPtr<const Top> pct2 = pt1;

但,同一个template的不同具现体之间并不存在什么与生俱来的固有关系(这里指若以带有bse-derived关系B,D类型分别具现化某个template,产生出来的两个具现体并不带有base-derived关系),所以编译器视SmartPtr<Middle>和SmartPtr<Top>为完全不同的class,它们之间的关系并不比vector<float>和Widget更密切。

为了获得我们希望获得的SmartPtr class之间的转换能力,我们必须将它们明确地编写出来。

在上述智能指针实例中,每一个语句创建了一个新式智能指针对象,所以现在我们应该关注如何编写智能指针的构造函数,使其行为能够满足我们的转型需要。

一个很具关键的观察结果是:我们永远无法写出我们需要的所有构造函数。在上述继承体系中,我们根据一个SmartPtr<Middle>或SmartPtr<Bottom>构造出一个SmartPtr<Top>,但若这个继承体系未来有所扩充,SmartPtr<Top>对象又必须能够根据其他智能指针构造自己。

就原理而言,此例中我们需要的构造函数数量没有止尽,因为一个template可悲无限量具现化,以致生成无限量函数。因此,似乎我们需要的不是为SmartPtr写一个构造函数,而是为它写一个构造模板。这样的模板是所谓member function template(常简称member template),其作用是为class生成函数:

template <typename T>
class SmartPtr {
public://member template,为了生成copy构造函数template<typenmae U>SmartPtr(const SmartPtr<U>& other);//...
};

上述代码的意思是,对任何类型T和任何类型U,这里可以根据SmartPtr<U>生成一个SmartPtr<T>。因为SmartPtr<T>有个构造函数接受一个SmartPtr<U>参数。

这一类构造函数根据对象u创建对象v,而u和v的类型是同一个template的不同具现体,有时称之为泛化copy构造函数。

完成声明之后,这个为SmartPtr而写的“泛化copy构造函数”提供的东西比我们需要的更多。对,我们希望根据一个SmartPtr<Bottom>创建一个SmartPtr<Top>,却不希望根据一个SmartPtr<Top>创建一个SmartPtr<Bottom>,因为那对pubic继承而言是矛盾的。我们也不希望根据一个SmartPtr<double>创建一个SmartPtr<int>,因为现实中并没有“将int*转换为double*”的对应隐式转换行为。

假设SmartPtr遵循auto_ptr和tr1::shared_ptr所提供的榜样,也提供一个get成员函数,返回智能指针对象所持有的那个原始指针的副本,那么我们可以在“构造模板”实现代码中约束转换行为,使它符合我们的期望:

template <typename T>
class SmartPtr {
public://以other的heldPtr初始化this的heldPtrtemplate<typenmae U>SmartPtr(const SmartPtr<U>& other):heldPtr(other.get()){/*...*/ }T* get() const { return heldptr; }//...
private:T* heldPtr;//这个SmartPtr持有的内置指针
};

上述代码的最终效益为SmartPtr<T>现在有了一个泛化copy构造函数,这个构造函数只在其所获得的实参隶属适当类型时才通过编译。

成员函数模板的效用不限于构造函数,它们常扮演的另一个角色是支持赋值操作。例如TR1的shared_ptr支持所有“来自兼容的内置指针、tr1::shared_ptr、auto_ptr和tr1::wear_ptr”构造行为,以及所有来自上述各物(tr1::wear_ptr除外)的赋值操作。

下面是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);//或shared_ptrtemplate<class Y>explicit shared_ptr(wear_ptr<Y> const& r);//或weak_ptrtemplate<class Y>explicit shared_ptr(auto_ptr<Y>& r);//或auto_ptrtemplate<class Y>//赋值,来自任何兼容的shared_ptr或auto_ptrshared_ptr& operator=(shared_ptr<Y> const& r);template<class Y>shared_ptr& operator=(auto_ptr<Y>& r);//...
};

上述所有构造函数都是explicit,唯有“泛化copy构造函数”除外。这意味从某个shared_ptr类型隐式转换至另一个shared_ptr类型是被允许的,但从某个内置指针或从其他智能指针类型进行隐式转换则不被认可(若是显式转换如cast强制转换动作倒是可以)。

member template并不改变语言规则,而语言规则说,若程序需要一个copy构造函数,你却没有声明它,编译器会为你暗自生成一个。在class内声明泛化copy构造函数(是个member template)并不会阻止编译器生成它们自己的copy构造函数(一个non-template),所以若你想要控制copy构造的方方面面,你必须同时声明泛化copy构造函数和“正常的”copy构造函数。

总结

1.请使用成员函数模板生成“可接受所有兼容类型”的函数。

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


http://www.ppmy.cn/news/790828.html

相关文章

js脚本简单说说

这篇介绍JavaScript方面的日志&#xff0c;我在是Clang上看到的。 有些时候你精通一门语言&#xff0c;但是会发现你其实整天在和其它语言打交道&#xff0c;也许你以为这些微不足道&#xff0c;不至于影响你的开发进度&#xff0c;但恰恰是这些你不重视的东西会浪费你很多时间…

如何使用python实现自动化办公?全网最全干货来了!

大家好&#xff0c;接下来我们来学习如何使用python 实现自动化办公&#xff0c;而不需要我们人工&#xff0c;或者说尽量减少我们人工的参与。&#xff08;文末领读者福利&#xff09; 自动化办公在我们的生活中非常的常见&#xff0c;让我们看看通过本博客你可以学习到pytho…

【机器学习核心总结】什么是随机森林

什么是随机森林 森林里有很多树&#xff0c;随机森林里有很多决策树。 随机森林是决策树的升级版&#xff0c;随机指的是树的生长过程。世上没有两片相同的树叶&#xff0c;随机森林中的树也各不相同。在构建决策树时&#xff0c;我们会从训练数据中有放回的随机选取一部分样本…

深度学习如何入门?

beanfrog &#xff0c;computer vision 161 人赞同 先了解个大概 A Deep Learning Tutorial: From Perceptrons to Algorithms 神经网络肯定是要学习的&#xff0c;主要是BP算法&#xff0c;可以看看PRML3、4、5三章&#xff0c;可先忽略其中的贝叶斯视角的解释。一些主要的算…

常用的前端插件V1

some jquery plugins are used for labelMangerSystem,some things may not be complete,ehhhh...,just leave them to perfection! flatpickr INTRODUCTION 轻量级(6k)&#xff0c;功能强大的日期选择器&#xff0c;兼容chrome和firefox 不依赖于其他库&#xff0c;UI少&#…

14 Python 办公自动化

目录 1、普通文件自动化管理 1.1 文件的复制 1.2 文件内容的复制 1.3 文件的裁剪 1.4 文件的删除 1.5 文件的压缩与解压缩 1.6 文件的查找 1.7 查找含有指定内容的文件 1.8 清理重复的文件 1.9 批量修改目录中的文件名称 2、文件夹的自动化管理 2.1 文件夹的复制 …

webpack5搭建与基本概念

webpack基础构建 新建文件夹进入文件夹查看是否安装node&#xff0c;命令&#xff1a;node-v创建package.json文件&#xff0c;命令&#xff1a;npm init -y安装webpack和webpack-cli&#xff0c;&#xff08;命令自动创建出package-lock.json文件和node_modules文件夹&#x…