C++中尽量使用C++提供的类型转换(2)---《More Effective C++》

C++中不仅有C语言提供的类型转换方式,而且自己还提供了新的转换方式,为什么C语言中有为什么我们还要提供呢?答案就是由于C风格的类型转换并不代表所有的类型转化,有一些严重的缺点,所以C++为了避免这些缺点,所以需要提供新的C++转换机制,C语言转换方式的缺点包括:
1)C语言中的类型转换可以在任何类型之间进行转换,及时这些类型转换中存在极大的不同,例如我们可以将一个指向const对象的指针转换为non-const指针,或者把一个指向基类的指针转化为指向紫烈的指针等等,传统C风格转换不对这些转化进行区分;
2)C风格的类型转换在程序中难以识别,显示转换或者隐式转化有时候都挺难识别的。C语言的类型转化操作符形式一般如:(type)expression;

C++为了解决这种问题,提供了4种新型类型转换操作符克服了C风格类型转换的缺点,分别是:static_cast、const_cast、dynamic_cast以及reinterpret_cast,这种新型类型转换的方式一般如:static_cast<type>(expression)。现在我们分别讲一下C++四种新型类型转化操作符。
1)static_cast
主要用于非多态类型的转换,不提供运行时候的检查来确保安全性。适用于以下场合:

  • 用于基本数据类型之间的转换,这种转换的安全性需要程序员来保证;
  • 把void指针转化为目标类型的指针,是极其不安全的;
  • 用于类层次结构中,父类和子类之间指针和引用的转换;
    ①上行转换,即将子类指针或引用用父类表示,这种转换时安全的;
    ②下行转化,即将父类指针用子类表示的时候,这种转化不安全,需要程序员用程序进行保证。什么意思呢?我们可以看看如下程序:
#include <iostream>
#include <string>
using namespace std;
class Base{
private:
    int i;
public:
    Base(){

    }
    Base(int i) :i(i){

    }
    virtual void show(){
        cout << 1 << " ";
        cout << i;
    }
    virtual ~Base(){

    }
};
class Derived :public Base{
private:
    int j;
public:
    Derived(){

    }
    Derived(int i, int j):Base(i),j(j){
    }
    virtual void show(){
        cout << 2 << " ";
        Base::show();
        cout<< " " << j;
        cout << " " << "这是Derived的show()";
    }
    void hello(){
        cout << "hello" << endl;
    }
    virtual ~Derived(){

    }
};
void show(Base* base){
    base->show();
}
int main(){
    Base* base = new Derived(10,20);
    show(base);
    cout << endl;
    static_cast<Derived*>(base)->hello();

    Derived* derived = new Derived(10, 20);
    show(static_cast<Base*>(derived));
    cout << endl;
    static_cast<Derived*>(base)->hello();

    //show(static_cast<Derived*>(base1));
    Base* base1 = new Base(10);
    show(static_cast<Derived*>(base1));
    cout << endl;
    static_cast<Derived*>(base1)->hello();
    return 0;
}

运行结果:
这里写图片描述

2)const_cast
用于去掉对象的const属性或者volatile属性。

class Widget{...};
class SpecialWidget:public Widget{
    ...
};
void update(SpecialWidget *psw);
SpecialWidget sw;//sw是个非const对象
const SpecialWidget& csw=sw;///csw是sw的一个引用,且是一个const对象
update(&csw);//ERROR,不能传递一个const SpecialWidget*变量给一个SpecialWidget*类型
update(const_cast<SpecialWidget*>(&csw));//OK
update((SpecialWidget*)&csw);//OK,C语言类型的一种转换,更加复杂,不容易识别

3)dynamic_cast
用于类层次之间的上行转化和下行转换,但需要注意的是,无论是上行转化或者下行转化,都需要包括指定转换对象的内容,要不即使编译通过也会在运行时候检测出错误。

#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Base{
private:
    int i;
public:
    Base(){

    }
    Base(int i) :i(i){

    }
    virtual void show(){
        cout << i << endl;
    }
    virtual ~Base(){

    }
};
class Derived :public Base{
private:
    int j;
public:
    Derived(){

    }
    Derived(int i, int j):Base(i),j(j){

    }
    virtual void show(){
        Base::show();
        cout << j << endl;
    }
    void hello(){
        cout << "hello" << endl;
    }
    virtual ~Derived(){

    }
};
void show(Base* base){
    base->show();
}
int main(){
    Base* base = new Base(10);
    if (typeid(dynamic_cast<Derived*>(base)) == typeid(Derived*)){
        cout << "dynamic_cast针对Base* base1 = new Base(10)转化成功" << endl;
    }
    //dynamic_cast<Derived*>(base)->show();

    Base* base1 = new Base(10);
    if (typeid(static_cast<Derived*>(base1)) == typeid(Derived*)){
        cout << "static_cast针对Base* base1 = new Base(10)转化成功" << endl;
    }
    else if (typeid(static_cast<Derived*>(base1)) == typeid(Base*)){
        cout << "static_cast针对Base* base1 = new Base(10)转化失败" << endl;
    }
    static_cast<Derived*>(base1)->show();
    return 0;
}

运行结果:
这里写图片描述

现在我们改变一些代码,看看dynamic_cast的转化效果:

#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Base{
private:
    int i;
public:
    Base(){

    }
    Base(int i) :i(i){

    }
    virtual void show(){
        cout << i << endl;
    }
    virtual ~Base(){

    }
};
class Derived :public Base{
private:
    int j;
public:
    Derived(){

    }
    Derived(int i, int j):Base(i),j(j){

    }
    virtual void show(){
        Base::show();
        cout << j << endl;
    }
    void hello(){
        cout << "hello" << endl;
    }
    virtual ~Derived(){

    }
};
void show(Base* base){
    base->show();
}
int main(){
    Base* base = new Base(10);
    if (typeid(dynamic_cast<Derived*>(base)) == typeid(Derived*)){
        cout << "dynamic_cast针对Base* base1 = new Base(10)转化成功" << endl;
    }
    dynamic_cast<Derived*>(base)->show();

    Base* base1 = new Base(10);
    if (typeid(static_cast<Derived*>(base1)) == typeid(Derived*)){
        cout << "static_cast针对Base* base1 = new Base(10)转化成功" << endl;
    }
    else if (typeid(static_cast<Derived*>(base1)) == typeid(Base*)){
        cout << "static_cast针对Base* base1 = new Base(10)转化失败" << endl;
    }
    //static_cast<Derived*>(base1)->show();
    return 0;
}

运行结果:
这里写图片描述

通过上述比较,我们可以发现dynamic_cast比static_cast更能确切地表达我们所需要的意思,而static_cast可能会导致一些误判,就如本例所示,进行一个下行转换,由于给出的为Base* base=new Base(10),然后下行转化后都变成了Derived*,但是其中并未实际包含Derived,因此,在调用Derived中的show()时候就会露馅,这点dynamic_cast做的完美,反观,static_cast敷衍了事,利用Base的show()函数以此充好,所以会引诱编程人员犯下很严重的错误。

4)reinterpret_cast
reinterpret_cast进行的类型转换,其转换结果几乎都是在执行期期间定义,因此,使用reinterpret_cast的代码很难移植。
reinter_pret的最普遍用途就是在函数指针类型之间进行类型转换。

typedef void (*FuncPtr)();
FuncPtr funcPtrArray[10];

int doSomething();

funcPtrArray[0]=&doSomething;//错误,类型无法匹配
funcPtrArray[0]=reinterpret_cast<FuncPtr>(&doSomething);//OK

转换函数指针的代码不可移植,在一些情况下这些转换将产生不正确的结果,所以需要避免转换函数指针类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值