c++

最好使用c++转型操作符

Posted by zhangxiaojian on July 12, 2014

C++使用四个新的转型操作符来代替传统C语言的转型方式:

1.static_cast(expression)

最常用的一种转型方式,几乎与旧式的C语言拥有相同的转型威力与意义。如将int转换为double等,但不能将int转化为一个自定义的strut类型,因为本身就不符合这种转化方式。

2.const_cast(expression)

针对对象的const特性提供的一种转型方式,用来去掉对象的const特性。如:

class Base{};
class Derived:public Base{};

定义一个子类一个父类,为了阅读方便,省略类的详细定义。接着再定义变量:

Derived d;
const Derived cd = &d;

对象cd是对象d的一个引用,但是被视为const对象。假设有一个需要Derived*作为参数的函数:

    void update(Derived* pd);

根据函数名可以推测,在函数中很有可能会改变对象pd的值,因此传一个const类型的指针不符合要求,语法也不能通过。因此需要去掉对象的常量性后调用。

    update(const_cast<Derived*>(&cd));

一定要记得,const_cast不能用于其它转型。如将Base对象转化为Derived对象,是不可能的。

Base b;
const_cast<Derived*>(&b);        //会报错,无法实现向下转型,向下转型
//需要使用dynamic_cast

3.dynamic_cast(expression)

使用方法和前两种一样,但是用于“安全的向下转型或者跨系转型操作”,可以实现父类类型转化为子类类型。转化失败之后,会以一个null指针(当转型对象是指针)或者一个exception(当转型对象是reference)表现出来。如下是一个完整的列子:

#include<iostream>
#include<stdexcept>

class Base{
    public:
        virtual void printname()
        {
            std::cout<<"base class"<<std::endl;
        }
};

class Derived:public Base{
    public:
        void printname()
        {
            std::cout<<"derived class"<<std::endl;
        }
};

void neednamep(Derived*);
void neednamer(Derived&);

int main()
{
    Base* pbase;
    Base base;
    Derived derived;

    //pbase = &derived;
    pbase = &base;
    //如果pbase本身不是指向derived类型的指针,那么转换结果返回的是null
    neednamep(dynamic_cast<Derived*>(pbase));  


    try{
        //如果pbase本身不是指向derived类型的指针,转换结果会抛出异常,
        //由于异常没有回调函数,会调用系统abort函数。
        neednamer(dynamic_cast<Derived&>(*pbase));   

    }catch(std::exception e)
    {
        std::cout<<"catch an exception..."<<std::endl;
    }
    int a;
    std::cin>>a;
    return 0;

}

void neednamep(Derived* pd)
{
    if(pd == NULL)
        std::cout<<"null"<<std::endl;
    else
        pd->printname();
}

void neednamer(Derived& rd)
{
    rd.printname();
}

整个程序执行结果:

>> null
>> catch an exception...

因为pbase本身指向的就是Base class类型,因此转型失败。

4.reinterpret_castexpression

这个转型操作的转换结果几乎总是与编译的平台息息相关,不具备移植性。最常用的用途是转换“函数指针”类型。

typedef void (*FuncPtr)();//定义函数指针类型
int fun();                //定义一个无参函数,返回值为int

FuncPtr funcArray[10];    //函数指针数组
funcArray[0] = reinterpret_cast<FuncPtr>(&fun);//函数类型转换

尽管如此,函数指针转型操作并不具备移植性,因此需要慎用。

就像标题所说,如果在旧式转换和C++提供的以上几种类型转换方式中选择,最好还是选择后者。