c++對象模型探索(一)
阿新 • • 發佈:2018-03-27
定義 發現 什麽 對象模型 是個 OS 並且 std out
粗略閱讀了《深度探索c++對象模型》一書後,對c++對象底層的內存布局有了一些了解,但同時,也產生了一些疑惑:
1、將子類指針用dynamic_cast轉成父類指針之後,其虛表指針會相應變化麽?
2、父類轉子類呢?
以下是驗證疑惑的代碼:
#include <iostream> class A { public: virtual void func() { std::cout << "a: " << a << std::endl; } int a = 1; }; class B : publicA { public: virtual void func() { std::cout << "b: " << b << std::endl; } int b = 2; }; int main() { A* pa1 = new B(); B* pb1 = (B*)pa1; B* pb2 = new B(); A* pa2 = dynamic_cast<A*>(pb2); A* pa3 = new A(); B* pb3 = dynamic_cast<B*>(pa3); pa1->func(); pb1->func(); pa2->func(); pb2->func(); pa3->func(); pb3->func(); return 0; }
編譯:g++ object.cpp -o main --std=c++11 -g
執行結果:
$ ./main b: 2 b: 2 b: 2 b: 2 a: 1 Segmentation fault
在pb3調用func的時候,發生了一個段錯誤。這個不大符合我的預期,查詢了下dynamic_cast的用法,發現:
‘dynamic_cast‘只用於對象的指針和引用。當用於多態類型時,它允許任意的隱式類型轉換以及相反過程。不過,與static_cast不同,在後一種情況裏(註:即隱式轉換的相反過程),dynamic_cast會檢查操作是否有效。也就是說,它會檢查轉換是否會返回一個被請求的有效的完整對象。 檢測在運行時進行。如果被轉換的指針不是一個被請求的有效完整的對象指針,返回值為NULL.
如上所說,當dynamic_cast檢測到轉換不成功的時候,返回的是個NULL指針,因此就不難解釋,為什麽會發生段錯誤了。
另外,A* pa2是從B*轉換過來的,但其實調用的還是類型B的方法,由此可以推斷,類型的虛表指針在類型分配內存的時候就確定了,dynamic_cast的轉換並不能將虛表指針重新賦值。
重新調整了下main函數代碼:
1 int main() { 2 A* pa1 = new B(); 3 B* pb1 = (B*)pa1; 4 5 B* pb2 = new B(); 6 A* pa2 = dynamic_cast<A*>(pb2); 7 A* pa21 = (A*)pb2; 8 A* pa22 = static_cast<A*>(pb2); 9 10 A* pa3 = new A(); 11 B* pb3 = static_cast<B*>(pa3); 12 13 pa1->func(); 14 pb1->func(); 15 pb2->func(); 16 pa2->func(); 17 pa21->func(); 18 pa22->func(); 19 pa3->func(); 20 pb3->func(); 21 return 0; 22 }
運行結果如下:
$ ./main b: 2 b: 2 b: 2 b: 2 b: 2 b: 2 a: 1 a: 1
可見,不管是強轉、static_cast還是dynamic_cast,都不會影響虛表指針,可以通過GDB來驗證下:
(gdb) p *pa1 $1 = {_vptr.A = 0x400d10 <vtable for B+16>, a = 1} (gdb) p *pb1 $2 = {<A> = {_vptr.A = 0x400d10 <vtable for B+16>, a = 1}, b = 2} (gdb) p *pb2 $3 = {<A> = {_vptr.A = 0x400d10 <vtable for B+16>, a = 1}, b = 2} (gdb) p *pa2 $4 = {_vptr.A = 0x400d10 <vtable for B+16>, a = 1} (gdb) p *pa21 $5 = {_vptr.A = 0x400d10 <vtable for B+16>, a = 1} (gdb) p *pa22 $6 = {_vptr.A = 0x400d10 <vtable for B+16>, a = 1} (gdb) p *pa3 $7 = {_vptr.A = 0x400d30 <vtable for A+16>, a = 1} (gdb) p *pb3 $8 = {<A> = {_vptr.A = 0x400d30 <vtable for A+16>, a = 1}, b = 0}
可以看到用new B() 方式定義的對象,虛表指針都是指向 B類的虛表指針,用new A()方式定義的對象,虛表指針都指向了A。
由此可以看出,對象的虛表指針,在定義的時候,就確定了,並且不會隨著強轉、static_cast或dynamic_cast改變。
c++對象模型探索(一)