注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

一路

To find the final symmetry & beauty

 
 
 

日志

 
 
 
 

SGI STL 源码阅读笔记5 隐式类型转换总结[原创]  

2011-02-15 21:57:32|  分类: c++学习笔记 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

    此篇日志是关于隐式类型转换的一个总结,为更好的阅读源码做一些准备。C++中类型的隐式转换随处可见,既然是隐式转换,编译器就要保证其中不会出现问题,这里就对这种转换做一个总结。

一、非常量引用到常量引用的转换不能通过常量引用来修改对象,这样如果把非常量引用转换为常量引用就是一种保守的转换,不会对对象产生任何的负面影响。这种转换较为简单不再详细描述。但这其有一个特别要注意的,就是转换为常量引用的非常量可能是一个没有名称的临时对象,比如下面的例子的函数定义,我可以这样调用这个函数,foo("inputtring");这样做是可以的原因是string函数有一个以const char* 为参数的变参数构造函数,如此使用就相当于先用此const char* 构造一个临时的stirng 对象,之后把这个对象转换为const引用,这样做不会出现什么问题,因为不能通过常量引用修改对象,编译器产生的临时对象不能在名称查找中找到,如果程序员的代码修改了命名的临时对象,那基本上可以认为这不是程序员的意愿,因此只有常量引用可以发生这种双转换,因非常量引用不可以。

Void foo(const string& str);

二、子类指针向父类指针和子类引用向父类引用的隐式转换,这种引用熟悉多态性的都已十分了解了,这里不详细说。

三、通过构造函数的转换。注意这里的构造函数,有很多书上有"泛化的复制构造函数",我个人认为根本不存在这种东西。复制构造函数就是要参数与自身类型一模一样,或是引量引用或是引用,如下代码。 

 

//filename type_conversion.cpp

//written by saturnman

#include<iostream>

#include"Tracer.h"

using namespace std;

//test inherit convertion

class Base

{

    public: 

};

class Derived:public Base

{

    public:

};

void testfunc1(Base& input)

{

}

void testfunc1(Base* input)

{

}

template<typename T>

class ClassA :public Tracer

{

    public:

        ClassA()

        {

        }

        ClassA(ClassA const& rhs)

        {

        }

        template<typename U>

        ClassA(ClassA<U> const& rhs)

        {

        }

        /*

        template<typename U>

        operator ClassA<U>()

        {

            cout<<"convertion operator called."<<endl;

            return ClassA<U>();

        }

        */

};

template<typename T>

class ClassB :public Tracer

{

    public:

        ClassB()

        {

        }

        ClassB(ClassB const& rhs)

        {

        }

        template<typename U>

        ClassB(ClassB<U> const& rhs)

        {

        }

        template<typename U>

        operator ClassB<U>()

        {

            cout<<"convertion operator called."<<endl;

            return ClassB<U>();

        }

};

ClassA<double> testfunc2(ClassA<double> const& rhs)

{ 

    return rhs;

}

ClassB<double> testfunc2(ClassB<double> const& rhs)

{

    return rhs;

}

int main()

{

    //test inherit convertion

    Derived d;

    testfunc1(d);//no error

    testfunc1(&d);//no error

    //test Constructor convertion

    ClassA<int> ca1;

    ClassA<int> ca2(ca1);//call base class Constructor not copy Constructor

    testfunc2(ca1);

    ClassB<int> cb1;

    testfunc2(cb1);     //call convertion operator but not Constructor

    return 0;

}

 

注意这部分代码,下面的函数声名被认为是一个泛型的复制构造函数,而且不会覆盖默认复制构造函数,其实从我的实验来说这个根本就是一个构造函数,当然不会覆盖默认复制构造函数,它只会覆盖默认构造函数。把复制构造函数声名为explicit的可以防止类型被在函数间以传值方式传递,但是把下面这个函数声名为explicit并不会影响类以值方式在函数间传递。这就说明我们我们并没有真正的把默认复制构造函数声明为explicit. 复制构造函数还在原地没动。因且还有一个证据就是就算是默认构造函数不写,让编译器来添加,而这个函数模板参数完全符合默认构造函数时这个函数也不会被调用,这些读者都可以自己写代码试。

template<typename U>

ClassA(ClassA<U> const& rhs)

{

}

四、通过类型转换操作符进行转换 ,这种方式的转换最为直接了,我在ClassB的代码中加入了泛型的的类型转换操作符,同时也加入了泛型的构造函数。但是从程序运行中可以看出类型转换造作符被优先调用了。

注:为了方便测试我这里实现了一个叫Tracer的类,代码如下。这个类有几个静态成员。这个写一个拥有静态成员的类做为模版类的基 类的方式与基于内存池的allocator的实现技术直接相关,SGI STL中没有使用这种技术,使得其中的allocator是无类型参数的(其中有的整型模版函数与多线程相关,我们暂时忽略它),这样的allocator是不合C++标准规范的,但是SGI STL通过一个simple_allocator的接口类做到了与标准相符合。GNU标准库中的代码就与SGI STL不相同 ,GNU的代码使用了我这里使用的技术,使得不同种类的allocator其实使用了同一个内存池。关于内存池在以后的日志中再介绍,下面是Tracer类的完整代码。 

 

//filename: tracer.h

//written by saturnman

#include<iostream>

using namespace std;

#ifndef _TRACER_H_

#define _TRACER_H_

class Tracer

{

    public:

        Tracer()

        {

            ++s_NoOfInstances;

            ++s_MaxNoOfInstances;

            m_instanceID = s_NoOfInstances;

            cout<<"Constructor called to create instance "<<m_instanceID<<endl;

        }

        Tracer(Tracer const& rhs)

        {

            //not really copy it

            ++s_NoOfInstances;

            ++s_MaxNoOfInstances;

            m_instanceID = s_NoOfInstances;

            cout<<"Copy Constructor called to create instance "<<m_instanceID<<endl;

        }

        static void report()

        {

            cout<<"Now there are "<<s_NoOfInstances<<" instances exist."<<endl;

            cout<<"There are maximum "<<s_MaxNoOfInstances<<" instances exist."<<endl;

        }

        Tracer& operator=(Tracer const& rhs)

        {

            cout<<"Assignment operator called."<<endl;

        }

        void Info()

        {

            cout<<"This is instance ID:"<<m_instanceID<<endl;

        }

        ~Tracer()

        {

            --s_NoOfInstances;

        }

    private:

        int m_instanceID;

        static int s_NoOfInstances;

        static int s_MaxNoOfInstances;

};

int Tracer::s_NoOfInstances = 0;

int Tracer::s_MaxNoOfInstances = 0;

#endif /*_TRACER_H_*/

 

Ref:

[1]. C++ Templates: the complete guide

[2]. Addison Wesley - Ruminations on C++:A Decade of Programming Insight and Experience

[3]. 《STL源码剖析》侯捷

  评论这张
 
阅读(827)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017