<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在玩 C 的時候,經常會用 void*
來指向一段記憶體地址開端,然後再將其強轉成尺度更小的 char*
或 int*
來丈量一段記憶體,參考如下程式碼:
int main() { void* ptr = malloc(sizeof(int) * 10); int* int_ptr = (int*)ptr; char* char_ptr = (char*)ptr; }
由於 C 的自由度比較大,想怎麼玩就怎麼玩,帶來的弊端就是容易隱藏著一些不易發現的bug,歸根到底還是程式設計師的功底不紮實,C++ 設計者覺得不能把程式設計師想的太厲害,應該要力所能及的幫助程式設計師避掉一些不必要的潛在 bug,並且還要盡最大努力的避免對效能有過多的傷害,所以就出現了 4 個強制型別轉換運運算元。
既然 C++ 做了歸類,必然就有其各自用途,接下來我們逐一和大家聊一下。
這是四個運運算元中最好理解的,玩過 C++ 的都知道,預設情況下是不能修改一個 const 變數,比如下面這樣:
int main() { const int i = 10; i = 12; }
這段程式碼肯定是要報錯的,那如果我一定要實現這個功能,如何做呢?這就需要用到 const_cast
去掉它的常數符號,然後對 i 進行操作即可,所以修改程式碼如下:
int main() { const int i = 10; auto j = const_cast<int*>(&i); *(j) = 12; }
從名字上看就是一個 重新解釋轉換,很顯然這個非常底層,如果大家玩過 windbg ,應該知道用 dt
命令可以將指定的記憶體地址按照某一個結構體丈量出來,比如說 C# 的 CLR 在觸發 GC 時,會有 gc_mechanisms
結構,參考程式碼如下:
0:000> dt WKS::gc_mechanisms 0x7ffb6ba96e60 coreclr!WKS::gc_mechanisms +0x000 gc_index : 1 +0x008 condemned_generation : 0n0 +0x00c promotion : 0n0 +0x010 compaction : 0n1 +0x014 loh_compaction : 0n0 +0x018 heap_expansion : 0n0 +0x01c concurrent : 0 +0x020 demotion : 0n0 +0x024 card_bundles : 0n1 +0x028 gen0_reduction_count : 0n0 +0x02c should_lock_elevation : 0n0 +0x030 elevation_locked_count : 0n0 +0x034 elevation_reduced : 0n0 +0x038 minimal_gc : 0n0 +0x03c reason : 0 ( reason_alloc_soh ) +0x040 pause_mode : 1 ( pause_interactive ) +0x044 found_finalizers : 0n0 +0x048 background_p : 0n0 +0x04c b_state : 0 ( bgc_not_in_process ) +0x050 allocations_allowed : 0n1 +0x054 stress_induced : 0n0 +0x058 entry_memory_load : 0 +0x05c exit_memory_load : 0
其實 reinterpret_cast 大概也是幹這個事的,參考程式碼如下:
typedef struct _Point { int x; int y; } Point; int main() { Point point = { 10,11 }; //記憶體地址 void* ptr = &point; //根據記憶體地址 丈量出 Point Point* ptr_point = reinterpret_cast<Point*>(ptr); printf("x=%d", ptr_point->x); }
從程式碼看,我直接根據 ptr
地址丈量出了 Point
結構,說實話這個和 C 玩法就比較類似了。
在多型場景下,有時候會遇到這樣的一個問題,一個父類別有多個子類,我現在手擁一個父類別,我不知道能不能將它轉換為其中一個子類,要試探一下看看,那怎麼去試探呢? 類似 C# 中的 as
運運算元,在 C++ 中就需要用 dynamic_cast
來做這件事情,參考如下:
//點 class Point { public: Point(int x, int y) :x(x), y(y) {} virtual void show() {} public: int x; int y; }; //矩形 class Rectangle :public Point { public: Rectangle(int x, int y, int w, int h) : Point(x, y), w(w), h(h) {} public: int w; int h; }; //三角形 class Triangle :public Point { public: Triangle(int x, int y, int z) :Point(x, y), z(z) {} public: int z; }; int main() { Point* p1 = new Rectangle(10, 20, 100, 200); Point* p2 = new Triangle(4, 5, 6); //將 p1 轉成 子類 Triangle 會報錯的 Triangle* t1 = dynamic_cast<Triangle*>(p1); if (t1 == nullptr) { printf("p1 不能轉成 Triangle"); } }
對,場景就是這個,p1 其實是 Rectangle
轉上去的, 這時候你肯定是不能將它向下轉成 Triangle
, 問題就在這裡,很多時候你並不知道此時的 p1 是哪一個子類。
接下來的一個問題是,C++ 並不像C# 有後設資料,那它是如何鑑別呢? 其實這用了 RTTI 技術,哪裡能看出來呢?哈哈,看組合啦。
Triangle* t1 = dynamic_cast<Triangle*>(p1); 00831D57 push 0 00831D59 push offset Triangle `RTTI Type Descriptor' (083C150h) 00831D5E push offset Point `RTTI Type Descriptor' (083C138h) 00831D63 push 0 00831D65 mov eax,dword ptr [p1] 00831D68 push eax 00831D69 call ___RTDynamicCast (083104Bh) 00831D6E add esp,14h 00831D71 mov dword ptr [t1],eax
從組合可以看到編譯器這是帶夾私貨了,在底層偷偷的呼叫了一個 ___RTDynamicCast
函數在執行時幫忙檢測的,根據 cdcel
呼叫協定,引數是從右到左,恢復成程式碼大概是這樣。
___RTDynamicCast(&p1, 0, &Point, &Triangle,0)
從名字上就能看出,這個強轉具有 static 語意,也就是 編譯階段
就生成好了,具體安全不安全,它就不管了,就拿上面的例子,將 dynamic_cast 改成 static_cast 看看有什麼微妙的變化。
int main() { Point* p1 = new Rectangle(10, 20, 100, 200); Point* p2 = new Triangle(4, 5, 6); Triangle* t1 = static_cast<Triangle*>(p1); printf("x=%d, y=%d,z=%d", t1->x, t1->y, t1->z); }
我們發現居然轉成功了,而且 Triangle
的值也是莫名奇怪,直接取了 Rectangle
的前三個值,如果這是生產程式碼,肯定要挨批了。。。
接下來簡單看下組合程式碼:
Triangle* t1 = static_cast<Triangle*>(p1); 00DF5B17 mov eax,dword ptr [p1] 00DF5B1A mov dword ptr [t1],eax printf("x=%d, y=%d,z=%d", t1->x, t1->y, t1->z); 00DF5B1D mov eax,dword ptr [t1] 00DF5B20 mov ecx,dword ptr [eax+0Ch] 00DF5B23 push ecx 00DF5B24 mov edx,dword ptr [t1] 00DF5B27 mov eax,dword ptr [edx+8] 00DF5B2A push eax 00DF5B2B mov ecx,dword ptr [t1] 00DF5B2E mov edx,dword ptr [ecx+4] 00DF5B31 push edx 00DF5B32 push offset string "x=%d, y=%d,z=%d" (0DF8C80h) 00DF5B37 call _printf (0DF145Bh) 00DF5B3C add esp,10h
從程式碼中看,它其實就是將 p1 的首地址給了 t1,然後依次把copy偏移值 +4,+8,+0C
, 除了轉換這個,還可以做一些 int ,long ,double 之間的強轉,當然也是一樣,編譯時組合程式碼就已經生成好了。
到此這篇關於一起聊聊C++中的四種型別轉換符 的文章就介紹到這了,更多相關C++類別型轉換符 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45