C_and_CPP 板


LINE

Sorry, 有很多地方错误,不得不指出来。 热心回答问题是好的,但是最好对内容有一定的把握,以免误导。 这一篇介绍 C++ 的四个关键字: static_cast, const_cast, reinterpret_cast, 以及 dynamic_cast 的意义用法。 学习任何编程语言,只单纯学习语法是不够的,要适当的运用某种语言机制,最好 要先知道该机制存在的目的,和什麽状况下会需要用到它,否则还不如不要使用。 ※ 引述《godfat (godfat 真常)》之铭言: : 静态转型,简单地说就是强制转型, : 只是不合理的转型 compiler 会告诉你不能这样转 : 例如两个毫无关联的物件 : class A{}; : class B{}; : A a; : static_cast<B>(a); // error static_cast 用於「相关型别」之间的转换,其目的是让编译器知道, 程序员是「有意识」的进行转换动作,并非不小心打错。例如: float f = 123.456f; int i = f; // 把 float 转为 int,编译器一般会给警告 int v = static_cast<int>(f); // 用 static_cast 通知编译器,设计意途确实如此 此外 static_cast 也可用於继承体系内的 downcast,例如: struct B { void f(); }; struct D : B { void g(); } d; B &b = d; ... b.f(); // ok b.g(); // 错误,b 是 reference to B 物件 static_cast<D&>(b).g(); // ok, 因为程序员知道 b 确实是参照某个 D 物件 : : const_cast : 单纯去掉物件的常数性 和/或 volatile 性 这里是对的。 : int const i = 10; : i = 5; // error : const_cast<int&>(i) = 5; // ok : (这边我不太确定是不是这样写,很少用) : (总之观念是这样) 举例有误。 const_cast 只是把常数性去掉,目的是方便设计,但是企图通过 const_cast 修改一个 const 物件,其结果未定义(视实作环境是否对该 const 物件采取 保护措施)。 至於 const_cast 使用的时机,通常是为了在不修改既有模组(例如没有 source code 的程式库)的情况下,解决两个模组之间 const-correctness 不相容的问题 (通常是不能改的那个模组,其设计不够周延)。例如: struct C { void f(); }; // 假设 C 是一个既存的模组(不能修改) void foo(C const &c) // foo 是自行设计的模组,c 物件只作为输入,不会被更动 { ... c.f(); // 由於 c 是 referece to const C 物件,但 C::f 并未被设计为 // const,因此这样写是不成立的。(编译器会给错误或至少警告) const_cast<C&>(c).f(); // ok, 用 const_cast 去掉 c 的常数性 } : : reinterpret_cast : 强迫 compiler 把输入型别视为欲转换的型别 : 这个不太好解释…总之就是暴力转型就对了 XD : 直接把该记忆体位置的资料视为欲转换的型别来看待 reinterpret_cast 几乎等於暴力转型(指 C-style 转型),但不能去掉物件 的常数性(也就是还不够暴力)。它用来处理任意型别之间的转换,通常是为 了争取运算或储存空间的效率时,所采取的低阶操作。例如: int IP_Addr = 0; char *p = reinterpret_cast<char*>(&IP_Addr); // 转型为 char *,以便於 // 以 Byte 为单位来处理 p[0] = 192; p[1] = 168; p[2] = 0; p[3] = 1; 传统的 C-style 转型相当於 static_cast, const_cast, reinterpret_cast 三合一(也就是暴力加三级)。 : 你漏了 dynamic_cast<> : 这跟 static_cast<> 有些类似 dynamic_cast 和 static_cast 无关。 : dynamic_cast<> 只能对於具有多形性型别转型, : 也就是他至少得要有一个 virtual function 这里是对的。dynamic_cast 是 RTTI 的一部份,它用来检测一个多型基底 类别的 pointer 或 reference 所参照物件的实际型别。例如: struct B1 { virtual void f() = 0; }; struct D1 { void f(); }; struct X : D1 { void f(); void g(); }; void foo(B1 *b1) // foo 模组并不知道 b1 所参照物件的实际型别 { if (dynamic_cast<D1*>(b1)) // 如果 b1 参照的是 D1 物件 { b1->f(); } else if (D1 *d1 = dynamic_cast<X*>(b1)) // 如果 b1 参照的是 X 物件 { d1->g(); } else { ... } } 此例中,dynamic_cast 的用法也是所谓的 downcast,但和 static_cast 不同的是,前者用於侦测未知多型物件的实际型别,而後者用於对已知物件 (可以是多型物件或普通物件)的转型。 可以看出,B1, D1, X 的继承体系设计并不是很理想,因为在这种情况下,应该 直接利用 virtual function 的动态多型机制,而非依赖 dynamic_cast 侦测物 件的型别。例如: struct B2 { virtual void f() = 0; virtual void g() = 0; }; struct D2 : B2 { void f(); void g(); } d2; struct Y : D2 { void f(); void g(); } y; void foo() { B2 *b2 = &d2; // b2 参照 D2 物件 b2->g(); // 实际上会执行 D2::g,不必依赖 dynamic_cast b2 = &y; // 换一下,改参照 Y 物件 b2->g(); // 实际上会执行 Y::g } 显然,B2, D2, Y 的设计比较合理。事实上,如果所有的模组都是自行设计, dynamic_cast 是多余的。但它之所以存在,其目的就是为了解决「既存模组 」不能修改的问题。(最常见的例子,就是缺乏源代码的程式库) 前面的例子中,如果 B1, D1 两模组不能修改,为了新扩充 X 模组,又要和 旧模组相容,dynamic_cast 在此情况下就能派上用场(反过来说,如果没有 dynamic_cast,问题就会变得很麻烦,而且各种替代方案都不太安全);但 如果完全是可自行控制的设计,就应该尽量遵循 B2, D2, Y 的方式来组织。 以上是 dynamic_cast 的功能中,downcast 的部份。另外,由於 C++ 支援 多重继承的机制,dynamic_cast 亦可用於 crosscast(横向转型),例如: struct Z : B1, B2 // 多重继承 { void f(); void g(); } z; void foo() { B1 *b1 = &z; B2 *b2 = dynamic_cast<B2*>(b1); // crosscast } 这个例子可以用来说明,dynamic_cast 实际上的动作是「型别检测」,而非 仅仅是「转型」,後者只是它输出的结果。此例中,b1 表面上是 (B1 *),但 它实际上参照的是 Z 物件,因此 dynamic_cast 侦测的结果,就是它可以顺 利转为 (B2 *) 。 : struct Base{virtual ~Base(){}}; : struct Derived: public Base{}; : Base pb = new Derived; : Derived pd = dynamic_cast<Derived*>(pb); : 如果 pb 真的是指向 Derived, 则 dynamic_cast<> 传回 pb 的地址 : 否的话,pd 为 NULL : boost 有提供 polymorphic_cast<>, 用处同 dynamic_cast<> : 差别在於错误时不是传回 NULL, 而是丢出 std::bad_cast : polymorphic_downcast<> 则是专门用来在已知必然成功的 downcast : 这种时候内建的 static_cast<> 和 dynamic_cast<> 其实都可以用, : 只是 static_cast<> 没有错误检查,dynamic_cast<> 效率太差 : polymorphic_downcast<> 则使用 assert(); 来检查是否成功 : http://www.boost.org/libs/conversion/cast.htm : : c-style cast : 等同於上面全部... : 在 C++ 中替他们分类,避免造成混淆 : 不过对初学者来说的话这麽多才是混淆吧,我猜 :p (下略) --



※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 59.120.214.120
1F:推 godfat:感谢指导,虽然我觉得跟我讲的没啥冲突 XD 大概是太随便了 03/13 01:44
※ 编辑: cppOrz 来自: 59.120.214.120 (03/13 04:50) crazying:转录至看板 NTUGIEE_EDA 03/13 11:58
2F:推 abovelight:推一个~了解更深入了 03/14 18:16







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:Tech_Job站内搜寻

TOP