C++雾中风景11:厘清C++类型转换(static_cast,dynamic_cast,reinterpret_cast,const_cast)

C++是一门弱类型的语言,提供了许多复杂和灵巧类型转换的方式。笔者之前写的Python与Go都是强类型的语言,对这种弱类型的设计实在是接受无力啊~~ ( 生活所迫,工作还得写C++啊~~)C++语言提供了四种类型转换的操作:static_cast,dynamic_cast,reinterpret_cast,const_cast,今天就来聊一聊,在C++之中应该如何来使用这些类型转换的。

1.旧式类型转换

开门见山,先聊聊笔者对类型转换的看法吧。从设计上看,一门面向对象的语言是不一样提供类型转换的,这种方式破坏了类型系统。C++为了兼容C也不得不吞下这个苦果,在实际进行编程工作的过程之中,并不太推荐大家使用类型转换。(Java在这里就做了一些妥协,在基本类型之中提供了类型转换。对于对象类型则不提供类型转换这种黑魔法

C++之中提供了两种类型转换的方式,第一种方式沿用了C语言之中的类型转换,称之为旧式类型转换。说起来也很简单,举个栗子:

char x = 'c';
int y = (int) x;

这是最简单的一个旧式类型转换,一个char类型被装换为一个int类型。但是这种旧式的类型转换是存在问题的:过于粗暴且极易失控,所以C++新提供了四种新式的类型转换来替代旧式的类型转换,这四种类型转换分别用于不用的转换场景,接下来笔者来一一梳理一下它们的用法。

2.新式的类型转换

C++语言提供了四种新式类型转换的操作:
static_cast,dynamic_cast,reinterpret_cast,const_cast,这些操作都依托了C++的模板来使用,标准的用法是

xxx_cast<转换类型>(转换参数)

这种新式转换优于旧式的转换就在于:编译器可以在转换期间进行更多的检查,对于一些不符合转换逻辑的转换进行一些纠错。而某些类型转换操作可以利用RTTI(运行时类型信息)来确保类型转换的合理,这是旧式的类型转换无法达成的效果。

  • const_cast

从名字上就可以看出来,这厮是用来对const属性进行类型转换的。这个名字取得有些偏颇,它同样适用于volatile属性。它可以为变量添加或接触上述属性,它也是新式转换之中唯一具有这个能力的转换方式,没有什么额外的坑,用户体验良好:(但是偶尔对于const属性的转换需要执行多步,先通过const_cast转换,再借助其他转换

//函数需要传递const属性的变量,如atoi
atoi(const_cast<const char*>(char_ptr))
  • static_cast

static_cast 是静态的转换形式,不通过运行时类型检查来保证转换的安全性。它主要用于如下场合:

  • 用于基本数据类型之间的转换,如把long转换成char,把int转换成char。

  • 用于面向对象编程之中基类与派生类之间的指针或引用转换。它分为两种
    上行转换(把派生类的指针或引用转换成基类)是安全的;
    下行转换(把基类指针或引用转换成派生类),由于没有运行时的动态类型检查,所以是不安全的。

  • 把非const属性的类型转换为const类型,但是不能将const类型转换为非const类型,这个得借助前文的const_cast。

  • void 的空指针转换成其他类型的的空指针。

上面的几种概念的比较好理解,这里笔者着重聊聊上下行转换:不啰嗦,看代码:

class Bird {
public:
    virtual void fly() {
        cout << "I can fly." << endl;
    }
};

class Penguin:public Bird {
public:
    void fly() {
        cout << "I can't fly." << endl;
    }
}; 

上述代码我们定义了两个类BirdPenguin

int main() {
    Penguin* p = new (std::nothrow) Penguin;
    Bird* b = static_cast<Bird *>(p);

    b->fly();
    return 0;
}

上行转换,将派生类转换为基类的指针,合法。

int main() {
    Bird* b = new (std::nothrow) Bird;
    Penguin* p = static_cast<Penguin *>(b);
    
    if (p != nullptr) {
          p->fly();
     } else {
       
    }
    return 0;
}

下行转换,将基类转换为派生类的指针,此时程序的行为是不确定的。并且编译期间并没有警告,这是一种十分危险的用法,所以使用时一定要谨小慎微。所以接下来就要请出下一种转换dynamic_cast,这是在对象基类和派生类之间转换推荐的一种方式。

  • dynamic_cast

dynamic_cast主要用于在类层次间进行上下行转换时,它与static_cast的最大的区别就在于dynamic_cast能够在运行时进行类型检查的功能,所以做起类型转换比static_cast更安全,但是dynamic_cast会耗费更多的系统资源。dynamic_cast是无法通过旧式类型转换完成的类型转换。

int main() {
    Bird* b = new (std::nothrow) Bird;
    Penguin* p = dynamic_cast<Penguin *>(b);
    if (p != nullptr) {
        p->fly();
    } else {
        cout << "cast failed" << endl;
    }
    return 0;
}

dynamic_cast对于非法的下行转换会返回空指针,所以可以在一定程度上避免不安全的类型转换。

  • reinterpret_cast
    reinterpret_cast主要用于指针类型之间的转换,和对象到指针类型之间的转换。reinterpret就是对数据的比特位重新解释转换为我们需要转换的对象。其与static_cast的区别在于其能处理有继承关系类的指针和内置数据类型的转换。而reinterpret_cast能够处理所有指针(引用)之间的转换
int main() {
    Bird* b = new (std::nothrow) Bird;
    Penguin* p = reinterpret_cast<Penguin *>(b);
    if (p != nullptr) {
        p->fly();
    } else {
        cout << "cast failed" << endl;
    }
    return 0;
}

上述代码依旧可以转换成功,结果不可控

3.小结

梳理完C++新引进的四种类型转换符之后,想必大家在实践之中可以很好的运用好这些C++的类型转换。后续笔者还会继续深入的探讨有关C++之中类型系统相关的内容,欢迎大家多多指教。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容