第七十六讲 细说map(2)

我们继续来看map,不过在继续说map之前我们来看看pair的最后一个复制构造函数,这是一个模板构造函数,这个函数的意思其实很简单,就是可以让我们实现这样的转换:
———————————-
pair<int,int>p =f(8.8, 9.2);


cout <<p.first <<"

"

<<p.second <<endl;

//输出8和9
———————————-

像我们看到的一样,上面这个转换毫无意义,从double转换到int会造成数据丢失,所以这不是我们所希望的,那怎么办呢?在这里面本身就没啥办法,所以这里我觉得是C++不完美的地方,不知道java又或者C#会是怎样,还好这种情况我们都能够理解了的,如果这种情况出现在智能指针中呢?其实很久以前就想和大家来谈这个话题的了,但是一直都没机会,现在又遇到了,我们的C++马上就结束了,所以趁着现在和大家谈一谈。

现在我们来看一个问题:
—————————–
class B{…… };


class D:public B{…… };


class E:public D{…… };


B* p1 = new D;
B* p2 = new E;


const B* p3 = p1;


——————————-

通常情况下,我们像上面这样用没啥问题,而且运行得很好,当然,这就是内置指针的神奇之处,因为D和E 是B的派生,所以我们从D*或者是E*转换到B*,同样,我们还可以轻松的从非const转换到const,这看上去很好,而且通常我们也这样用,直到我们打算用对象来管理资源的时候……还记得我们以前写过一个智能指针吗
——————————–
template<typename T>
class SmPt{
public:

SmPt():point(new T){ }

SmPt(const T&

T0):point(new T(T0)){ }
////////////
……
……
////////////

};


———————————–
如果大家不记得这个智能指针的class,可以回头去看看我们的引用计数的那些章节吧,所以,如果我们打算用这个智能指针来管理我们资源的话,上面的情况就会变成下面这样:
———————————–
SmPt<B>p1 = SmPt<D>(new D);


SmPt<B>p2 = SmPt<E>(new E);


SmPt<const B>p3 = p1;


————————————

这看上去好像没问题,但是如果我们把模板展开,就知道有大问题了,首先我们来看第一句:SmPt<B>p1 = SmPt<D>(new D),这句代码展开后………………一个是B的具体化,一个却是D的具体化,原本B和D还算是有些关系的,但是现在是SmPt<B>和SmPt<D>,他们之间现在可以说是风马牛不相及,就像int和string一样,毫无任何关系,同样接下来的两句一样是毫无任何瓜葛,所以上面的代码是无法通过编译的,那么我们要怎么解决这个问题呢?这就是我们今天要说的话——写一个接受所有兼容类型的模板函数。

为了上面的代码能够完美的进行编译,所以我们只能写一个模板成员函数:
——————————————
SmPt(const SmPt<U>&

T0);


——————————————-
Ok,就这么简单,我们通过一个U构造一个T对象,上面的代码可以完美编译了,当然这不但可以完成我们想要的任务,而且比我想象的还要多,因为他还可以完成我们不想要的转换:
————————————–
SmPt<D>p = SmPt<B>(new B);


————————————–
这个转换是毫无意义,但是他却毫无征兆的通过编译,这可能会带来某种意想不到的bug,所以这种转换我们得避免,还记得我们SmPt里面有个get函数吗?
————————————–
T* get() const{

return point;

//point是T* point;

//如果不记得,还是可以回去看看引用计数那些章节的,里面有细说。
}
————————————–
有了这个函数,我们就可以避免那些毫无意义的转换了:
——————————————-
SmPt(const SmPt<U>&

T0):point(T0.get()){ }
——————————————-
现在只有能够通过隐式转换让U*转换成T*的情况下才能够通过编译。
Ok,今天就到这里吧,不过,最后还得说一下,模板复制构造函数或者模板赋值操作符并不是真正的我们平时所说的复制构造函数和赋值操作符,所以,当我们没有写赋值操作符或者是复制构造函数时,尽管我们写下模板赋值或者复制,编译器还是会为我们生成复制或者赋值操作符的。

==================================
回复D直接查看目录

原文始发于微信公众号(

C/C++的编程教室

):第七十六讲 细说map(2)

|

发表评论