本文主要探讨c++相关知识。
类大小:
空类大小为1字节
虚函数表(vptr)大小4个字节
继承需要交基类大小,虚继承的派生类也有vptr
静态成员在静态区域不占内存
成员函数地址在代码段不占字节
继承本质是代码复用,class默认是private继承,struct默认是public继承
外部只能访问对象public成员,protected和private成员无法直接访问,派生类可继承private成员却无法直接访问,基类定义protected成员被派生类访问不被外部访问
派生类继承基类所有成员除构造和析构,派生类继承的成员初始化和析构由基类构造和析构完成
重载是同一作用域且函数名相同,参数列表不同,隐藏是派生类隐藏基类同名成员
静态绑定在编译时确定调用,调用效率高但灵活性低适用于非虚函数,函数重载,普通函数调用,动态绑定在运行时确定调用,调用效率低但灵活性高,适用于虚函数调用和多态
类定义虚函数在编译时产生vftable函数表(类中添加vptr指向vftable),vftable存储RTTI指针和虚函数地址,运行时将虚函数表加载到.rodata
类定义虚函数则类定义对象后运行时会存储vfptr虚函数指针指向相应虚函数表vftable,定义多个对象时vfpt指向同一虚函数表,类中虚函数个数不影响对象大小影响虚函数表大小
派生和基类方法、返回值、函数名、参数相同,基类为虚函数派生类方法自动为成虚函数,构造函数函数都是静态绑定,包括构造函数中的虚函数
析构函数不为虚函数(动态绑定),基类指针指向派生类时,析构函数静态绑定成基类析构函数,派生类开辟的内存由于不能调用派生类析构函数而泄漏内存
基类指针指向堆开辟的派生类对象,delete基类指针调用析构函数必须为动态绑定(基类为虚析构)
静态多态(编译):函数重载,模板(函数模板,类模板),动态多态(运行):基基类指针(引用)指向派生类对象通过该指针(引用)调用同名覆盖的虚函数
抽象类不能实例化对象可定义指针和引用变量,类对象通过该指针(引用)调用同名覆盖的虚函数
成员方法调用在运行阶段确定,默认参数和访问权限在编译阶段(字面判断调用)确定,静态绑定时运行时确定,动态绑定时运行时确定
基类和派生类的存储类型和顺序:
class C
{public:int a;int b;virtual void func1() = 0;void func2();
};class C1 : public class C
{public:int c;virtual void func1() = 0;virtual void func3() = 0;void func4();
};
demo1:
静态绑定,动态绑定
结构图
代码示例:
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.28) #最低版本要求SET(CMAKE_CXX_COMPILER "g++-11") #设置g++编译器PROJECT(CLASS) #设置工程名MESSAGE(STATUS "CPP test") #打印消息ADD_EXECUTABLE(pro test.cpp) #生成可执行文件
run.sh
#!/bin/bashif [ -f ./Makefile ]
thenmake clean
ficmake .makeecho "---------------------------------"./prog++ test.cpp -o test -gobjdump -S test > test.dis
clean.sh
rm -rf CMakeCache.txt CMakeFiles Makefile cmake_install.cmake *.o pro test test.dis
test.cpp
#include <iostream>class C
{public:void func(){std::cout << "C::func()" << std::endl;}
};class C1 : public C
{public:void func(){std::cout << "C1::func()" << std::endl;}
};class C2
{public:virtual void func(){std::cout << "C2:func()" << std::endl;}
};class C3 : public C2
{public:void func(){std::cout << "C3::func()" << std::endl;}
};class C4
{public:virtual void func(){std::cout << "C4::func()" << std::endl; }C4(){std::cout << "C4()" << std::endl;func();}
};int main()
{C c;C1 c1;C2 c2;C3 c3;//静态绑定(编译时确定)c.func();c1.func();c2.func();c3.func();C *pc = &c1;pc->func(); //静态绑定(编译时确定)C2 *pc2 = &c3;pc2->func(); //动态绑定(运行时确定)pc = &c; //静态绑定(编译时确定)pc->func();C1 *pc1 = &c1; //静态绑定(编译时确定)pc1->func();pc2 = &c2; //动态绑定(运行时确定)pc2->func();C3 *pc3 = &c3;pc3->func(); //动态绑定(运行时确定)C4 c4; //定义在构造函数中的虚函数为静态绑定(编译时确定)return 0;
}
结果示例:
结果图:
test.dis
test.dis
test: 文件格式 elf64-x86-64Disassembly of section .init:0000000000001000 <_init>:1000: f3 0f 1e fa endbr641004: 48 83 ec 08 sub $0x8,%rsp1008: 48 8b 05 e1 2f 00 00 mov 0x2fe1(%rip),%rax # 3ff0 <__gmon_start__@Base>100f: 48 85 c0 test %rax,%rax1012: 74 02 je 1016 <_init+0x16>1014: ff d0 call *%rax1016: 48 83 c4 08 add $0x8,%rsp101a: c3 retDisassembly of section .plt:0000000000001020 <.plt>:1020: ff 35 82 2f 00 00 push 0x2f82(%rip) # 3fa8 <_GLOBAL_OFFSET_TABLE_+0x8>1026: ff 25 84 2f 00 00 jmp *0x2f84(%rip) # 3fb0 <_GLOBAL_OFFSET_TABLE_+0x10>102c: 0f 1f 40 00 nopl 0x0(%rax)1030: f3 0f 1e fa endbr641034: 68 00 00 00 00 push $0x01039: e9 e2 ff ff ff jmp 1020 <_init+0x20>103e: 66 90 xchg %ax,%ax1040: f3 0f 1e fa endbr641044: 68 01 00 00 00 push $0x11049: e9 d2 ff ff ff jmp 1020 <_init+0x20>104e: 66 90 xchg %ax,%ax1050: f3 0f 1e fa endbr641054: 68 02 00 00 00 push $0x21059: e9 c2 ff ff ff jmp 1020 <_init+0x20>105e: 66 90 xchg %ax,%axDisassembly of section .plt.got:0000000000001060 <__cxa_finalize@plt>:1060: f3 0f 1e fa endbr641064: ff 25 66 2f 00 00 jmp *0x2f66(%rip) # 3fd0 <__cxa_finalize@GLIBC_2.2.5>106a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)Disassembly of section .plt.sec:0000000000001070 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>:1070: f3 0f 1e fa endbr641074: ff 25 3e 2f 00 00 jmp *0x2f3e(%rip) # 3fb8 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@GLIBCXX_3.4>107a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)0000000000001080 <_ZNSolsEPFRSoS_E@plt>:1080: f3 0f 1e fa endbr641084: ff 25 36 2f 00 00 jmp *0x2f36(%rip) # 3fc0 <_ZNSolsEPFRSoS_E@GLIBCXX_3.4>108a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)0000000000001090 <__stack_chk_fail@plt>:1090: f3 0f 1e fa endbr641094: ff 25 2e 2f 00 00 jmp *0x2f2e(%rip) # 3fc8 <__stack_chk_fail@GLIBC_2.4>109a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)Disassembly of section .text:00000000000010a0 <_start>:10a0: f3 0f 1e fa endbr6410a4: 31 ed xor %ebp,%ebp10a6: 49 89 d1 mov %rdx,%r910a9: 5e pop %rsi10aa: 48 89 e2 mov %rsp,%rdx10ad: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp10b1: 50 push %rax10b2: 54 push %rsp10b3: 45 31 c0 xor %r8d,%r8d10b6: 31 c9 xor %ecx,%ecx10b8: 48 8d 3d ca 00 00 00 lea 0xca(%rip),%rdi # 1189 <main>10bf: ff 15 1b 2f 00 00 call *0x2f1b(%rip) # 3fe0 <__libc_start_main@GLIBC_2.34>10c5: f4 hlt10c6: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)10cd: 00 00 00 00000000000010d0 <deregister_tm_clones>:10d0: 48 8d 3d 39 2f 00 00 lea 0x2f39(%rip),%rdi # 4010 <__TMC_END__>10d7: 48 8d 05 32 2f 00 00 lea 0x2f32(%rip),%rax # 4010 <__TMC_END__>10de: 48 39 f8 cmp %rdi,%rax10e1: 74 15 je 10f8 <deregister_tm_clones+0x28>10e3: 48 8b 05 fe 2e 00 00 mov 0x2efe(%rip),%rax # 3fe8 <_ITM_deregisterTMCloneTable@Base>10ea: 48 85 c0 test %rax,%rax10ed: 74 09 je 10f8 <deregister_tm_clones+0x28>10ef: ff e0 jmp *%rax10f1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)10f8: c3 ret10f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)0000000000001100 <register_tm_clones>:1100: 48 8d 3d 09 2f 00 00 lea 0x2f09(%rip),%rdi # 4010 <__TMC_END__>1107: 48 8d 35 02 2f 00 00 lea 0x2f02(%rip),%rsi # 4010 <__TMC_END__>110e: 48 29 fe sub %rdi,%rsi1111: 48 89 f0 mov %rsi,%rax1114: 48 c1 ee 3f shr $0x3f,%rsi1118: 48 c1 f8 03 sar $0x3,%rax111c: 48 01 c6 add %rax,%rsi111f: 48 d1 fe sar $1,%rsi1122: 74 14 je 1138 <register_tm_clones+0x38>1124: 48 8b 05 cd 2e 00 00 mov 0x2ecd(%rip),%rax # 3ff8 <_ITM_registerTMCloneTable@Base>112b: 48 85 c0 test %rax,%rax112e: 74 08 je 1138 <register_tm_clones+0x38>1130: ff e0 jmp *%rax1132: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)1138: c3 ret1139: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)0000000000001140 <__do_global_dtors_aux>:1140: f3 0f 1e fa endbr641144: 80 3d 05 30 00 00 00 cmpb $0x0,0x3005(%rip) # 4150 <completed.0>114b: 75 2b jne 1178 <__do_global_dtors_aux+0x38>114d: 55 push %rbp114e: 48 83 3d 7a 2e 00 00 cmpq $0x0,0x2e7a(%rip) # 3fd0 <__cxa_finalize@GLIBC_2.2.5>1155: 00 1156: 48 89 e5 mov %rsp,%rbp1159: 74 0c je 1167 <__do_global_dtors_aux+0x27>115b: 48 8b 3d a6 2e 00 00 mov 0x2ea6(%rip),%rdi # 4008 <__dso_handle>1162: e8 f9 fe ff ff call 1060 <__cxa_finalize@plt>1167: e8 64 ff ff ff call 10d0 <deregister_tm_clones>116c: c6 05 dd 2f 00 00 01 movb $0x1,0x2fdd(%rip) # 4150 <completed.0>1173: 5d pop %rbp1174: c3 ret1175: 0f 1f 00 nopl (%rax)1178: c3 ret1179: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)0000000000001180 <frame_dummy>:1180: f3 0f 1e fa endbr641184: e9 77 ff ff ff jmp 1100 <register_tm_clones>0000000000001189 <main>:func();}
};int main()
{1189: f3 0f 1e fa endbr64118d: 55 push %rbp118e: 48 89 e5 mov %rsp,%rbp1191: 48 83 ec 50 sub $0x50,%rsp1195: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax119c: 00 00 119e: 48 89 45 f8 mov %rax,-0x8(%rbp)11a2: 31 c0 xor %eax,%eaxC c;C1 c1;C2 c2;11a4: 48 8d 05 b5 2b 00 00 lea 0x2bb5(%rip),%rax # 3d60 <_ZTV2C2+0x10>11ab: 48 89 45 c0 mov %rax,-0x40(%rbp)C3 c3;11af: 48 8d 05 92 2b 00 00 lea 0x2b92(%rip),%rax # 3d48 <_ZTV2C3+0x10>11b6: 48 89 45 c8 mov %rax,-0x38(%rbp)//静态绑定(编译时确定)c.func();11ba: 48 8d 45 be lea -0x42(%rbp),%rax11be: 48 89 c7 mov %rax,%rdi11c1: e8 d8 00 00 00 call 129e <_ZN1C4funcEv>c1.func();11c6: 48 8d 45 bf lea -0x41(%rbp),%rax11ca: 48 89 c7 mov %rax,%rdi11cd: e8 0a 01 00 00 call 12dc <_ZN2C14funcEv>c2.func();11d2: 48 8d 45 c0 lea -0x40(%rbp),%rax11d6: 48 89 c7 mov %rax,%rdi11d9: e8 3c 01 00 00 call 131a <_ZN2C24funcEv>c3.func();11de: 48 8d 45 c8 lea -0x38(%rbp),%rax11e2: 48 89 c7 mov %rax,%rdi11e5: e8 6e 01 00 00 call 1358 <_ZN2C34funcEv>C *pc = &c1;11ea: 48 8d 45 bf lea -0x41(%rbp),%rax11ee: 48 89 45 d8 mov %rax,-0x28(%rbp)pc->func(); //静态绑定(编译时确定)11f2: 48 8b 45 d8 mov -0x28(%rbp),%rax11f6: 48 89 c7 mov %rax,%rdi11f9: e8 a0 00 00 00 call 129e <_ZN1C4funcEv>C2 *pc2 = &c3;11fe: 48 8d 45 c8 lea -0x38(%rbp),%rax1202: 48 89 45 e0 mov %rax,-0x20(%rbp)pc2->func(); //动态绑定(运行时确定)1206: 48 8b 45 e0 mov -0x20(%rbp),%rax120a: 48 8b 00 mov (%rax),%rax120d: 48 8b 10 mov (%rax),%rdx1210: 48 8b 45 e0 mov -0x20(%rbp),%rax1214: 48 89 c7 mov %rax,%rdi1217: ff d2 call *%rdxpc = &c; //静态绑定(编译时确定)1219: 48 8d 45 be lea -0x42(%rbp),%rax121d: 48 89 45 d8 mov %rax,-0x28(%rbp)pc->func();1221: 48 8b 45 d8 mov -0x28(%rbp),%rax1225: 48 89 c7 mov %rax,%rdi1228: e8 71 00 00 00 call 129e <_ZN1C4funcEv>C1 *pc1 = &c1; //静态绑定(编译时确定)122d: 48 8d 45 bf lea -0x41(%rbp),%rax1231: 48 89 45 e8 mov %rax,-0x18(%rbp)pc1->func();1235: 48 8b 45 e8 mov -0x18(%rbp),%rax1239: 48 89 c7 mov %rax,%rdi123c: e8 9b 00 00 00 call 12dc <_ZN2C14funcEv>pc2 = &c2; //动态绑定(运行时确定)1241: 48 8d 45 c0 lea -0x40(%rbp),%rax1245: 48 89 45 e0 mov %rax,-0x20(%rbp)pc2->func();1249: 48 8b 45 e0 mov -0x20(%rbp),%rax124d: 48 8b 00 mov (%rax),%rax1250: 48 8b 10 mov (%rax),%rdx1253: 48 8b 45 e0 mov -0x20(%rbp),%rax1257: 48 89 c7 mov %rax,%rdi125a: ff d2 call *%rdxC3 *pc3 = &c3;125c: 48 8d 45 c8 lea -0x38(%rbp),%rax1260: 48 89 45 f0 mov %rax,-0x10(%rbp)pc3->func(); //动态绑定(运行时确定)1264: 48 8b 45 f0 mov -0x10(%rbp),%rax1268: 48 8b 00 mov (%rax),%rax126b: 48 8b 10 mov (%rax),%rdx126e: 48 8b 45 f0 mov -0x10(%rbp),%rax1272: 48 89 c7 mov %rax,%rdi1275: ff d2 call *%rdxC4 c4; //定义在构造函数中的虚函数为静态绑定(编译时确定)1277: 48 8d 45 d0 lea -0x30(%rbp),%rax127b: 48 89 c7 mov %rax,%rdi127e: e8 51 01 00 00 call 13d4 <_ZN2C4C1Ev>return 0;1283: b8 00 00 00 00 mov $0x0,%eax
}1288: 48 8b 55 f8 mov -0x8(%rbp),%rdx128c: 64 48 2b 14 25 28 00 sub %fs:0x28,%rdx1293: 00 00 1295: 74 05 je 129c <main+0x113>1297: e8 f4 fd ff ff call 1090 <__stack_chk_fail@plt>129c: c9 leave129d: c3 ret000000000000129e <_ZN1C4funcEv>:void func()129e: f3 0f 1e fa endbr6412a2: 55 push %rbp12a3: 48 89 e5 mov %rsp,%rbp12a6: 48 83 ec 10 sub $0x10,%rsp12aa: 48 89 7d f8 mov %rdi,-0x8(%rbp)std::cout << "C::func()" << std::endl;12ae: 48 8d 05 4f 0d 00 00 lea 0xd4f(%rip),%rax # 2004 <_IO_stdin_used+0x4>12b5: 48 89 c6 mov %rax,%rsi12b8: 48 8d 05 81 2d 00 00 lea 0x2d81(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>12bf: 48 89 c7 mov %rax,%rdi12c2: e8 a9 fd ff ff call 1070 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>12c7: 48 8b 15 0a 2d 00 00 mov 0x2d0a(%rip),%rdx # 3fd8 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>12ce: 48 89 d6 mov %rdx,%rsi12d1: 48 89 c7 mov %rax,%rdi12d4: e8 a7 fd ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>}12d9: 90 nop12da: c9 leave12db: c3 ret00000000000012dc <_ZN2C14funcEv>:void func()12dc: f3 0f 1e fa endbr6412e0: 55 push %rbp12e1: 48 89 e5 mov %rsp,%rbp12e4: 48 83 ec 10 sub $0x10,%rsp12e8: 48 89 7d f8 mov %rdi,-0x8(%rbp)std::cout << "C1::func()" << std::endl;12ec: 48 8d 05 1b 0d 00 00 lea 0xd1b(%rip),%rax # 200e <_IO_stdin_used+0xe>12f3: 48 89 c6 mov %rax,%rsi12f6: 48 8d 05 43 2d 00 00 lea 0x2d43(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>12fd: 48 89 c7 mov %rax,%rdi1300: e8 6b fd ff ff call 1070 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>1305: 48 8b 15 cc 2c 00 00 mov 0x2ccc(%rip),%rdx # 3fd8 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>130c: 48 89 d6 mov %rdx,%rsi130f: 48 89 c7 mov %rax,%rdi1312: e8 69 fd ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>}1317: 90 nop1318: c9 leave1319: c3 ret000000000000131a <_ZN2C24funcEv>:virtual void func()131a: f3 0f 1e fa endbr64131e: 55 push %rbp131f: 48 89 e5 mov %rsp,%rbp1322: 48 83 ec 10 sub $0x10,%rsp1326: 48 89 7d f8 mov %rdi,-0x8(%rbp)std::cout << "C2:func()" << std::endl;132a: 48 8d 05 e8 0c 00 00 lea 0xce8(%rip),%rax # 2019 <_IO_stdin_used+0x19>1331: 48 89 c6 mov %rax,%rsi1334: 48 8d 05 05 2d 00 00 lea 0x2d05(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>133b: 48 89 c7 mov %rax,%rdi133e: e8 2d fd ff ff call 1070 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>1343: 48 8b 15 8e 2c 00 00 mov 0x2c8e(%rip),%rdx # 3fd8 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>134a: 48 89 d6 mov %rdx,%rsi134d: 48 89 c7 mov %rax,%rdi1350: e8 2b fd ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>}1355: 90 nop1356: c9 leave1357: c3 ret0000000000001358 <_ZN2C34funcEv>:void func()1358: f3 0f 1e fa endbr64135c: 55 push %rbp135d: 48 89 e5 mov %rsp,%rbp1360: 48 83 ec 10 sub $0x10,%rsp1364: 48 89 7d f8 mov %rdi,-0x8(%rbp)std::cout << "C3::func()" << std::endl;1368: 48 8d 05 b4 0c 00 00 lea 0xcb4(%rip),%rax # 2023 <_IO_stdin_used+0x23>136f: 48 89 c6 mov %rax,%rsi1372: 48 8d 05 c7 2c 00 00 lea 0x2cc7(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>1379: 48 89 c7 mov %rax,%rdi137c: e8 ef fc ff ff call 1070 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>1381: 48 8b 15 50 2c 00 00 mov 0x2c50(%rip),%rdx # 3fd8 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>1388: 48 89 d6 mov %rdx,%rsi138b: 48 89 c7 mov %rax,%rdi138e: e8 ed fc ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>}1393: 90 nop1394: c9 leave1395: c3 ret0000000000001396 <_ZN2C44funcEv>:virtual void func()1396: f3 0f 1e fa endbr64139a: 55 push %rbp139b: 48 89 e5 mov %rsp,%rbp139e: 48 83 ec 10 sub $0x10,%rsp13a2: 48 89 7d f8 mov %rdi,-0x8(%rbp)std::cout << "C4::func()" << std::endl; 13a6: 48 8d 05 81 0c 00 00 lea 0xc81(%rip),%rax # 202e <_IO_stdin_used+0x2e>13ad: 48 89 c6 mov %rax,%rsi13b0: 48 8d 05 89 2c 00 00 lea 0x2c89(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>13b7: 48 89 c7 mov %rax,%rdi13ba: e8 b1 fc ff ff call 1070 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>13bf: 48 8b 15 12 2c 00 00 mov 0x2c12(%rip),%rdx # 3fd8 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>13c6: 48 89 d6 mov %rdx,%rsi13c9: 48 89 c7 mov %rax,%rdi13cc: e8 af fc ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>}13d1: 90 nop13d2: c9 leave13d3: c3 ret00000000000013d4 <_ZN2C4C1Ev>:C4()13d4: f3 0f 1e fa endbr6413d8: 55 push %rbp13d9: 48 89 e5 mov %rsp,%rbp13dc: 48 83 ec 10 sub $0x10,%rsp13e0: 48 89 7d f8 mov %rdi,-0x8(%rbp){13e4: 48 8d 15 45 29 00 00 lea 0x2945(%rip),%rdx # 3d30 <_ZTV2C4+0x10>13eb: 48 8b 45 f8 mov -0x8(%rbp),%rax13ef: 48 89 10 mov %rdx,(%rax)std::cout << "C4()" << std::endl;13f2: 48 8d 05 40 0c 00 00 lea 0xc40(%rip),%rax # 2039 <_IO_stdin_used+0x39>13f9: 48 89 c6 mov %rax,%rsi13fc: 48 8d 05 3d 2c 00 00 lea 0x2c3d(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>1403: 48 89 c7 mov %rax,%rdi1406: e8 65 fc ff ff call 1070 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>140b: 48 8b 15 c6 2b 00 00 mov 0x2bc6(%rip),%rdx # 3fd8 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>1412: 48 89 d6 mov %rdx,%rsi1415: 48 89 c7 mov %rax,%rdi1418: e8 63 fc ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>func();141d: 48 8b 45 f8 mov -0x8(%rbp),%rax1421: 48 89 c7 mov %rax,%rdi1424: e8 6d ff ff ff call 1396 <_ZN2C44funcEv>}1429: 90 nop142a: c9 leave142b: c3 retDisassembly of section .fini:000000000000142c <_fini>:142c: f3 0f 1e fa endbr641430: 48 83 ec 08 sub $0x8,%rsp1434: 48 83 c4 08 add $0x8,%rsp1438: c3 ret
demo2:
类定义虚函数在编译时产生vftable函数表(类中添加vptr指向vftable),vftable存储RTTI指针和虚函数地址,运行时将虚函数表加载到.rodata
结构图:
代码示例:
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.28) #最低版本要求SET(CMAKE_CXX_COMPILER "g++-11") #设置g++编译器PROJECT(CLASS) #设置工程名MESSAGE(STATUS "CPP test") #打印消息ADD_EXECUTABLE(pro test.cpp) #生成可执行文件
run.sh
#!/bin/bashif [ -f ./Makefile ]
thenmake clean
ficmake .makeecho "---------------------------------"./prog++ test.cpp -o test -gobjdump -S test > test.dis
clean.sh
rm -rf CMakeCache.txt CMakeFiles Makefile cmake_install.cmake *.o pro test test.dis
test.cpp
#include <iostream>class People
{public:People(std::string name):name(name){};virtual void print_sex() = 0;protected:std::string name;
};class Man : public People
{public:Man(std::string name):People(name){};void print_sex() {std::cout << "man" << std::endl;}
};class Woman : public People
{public:Woman(std::string name):People(name){};void print_sex(){std::cout << "woman" << std::endl;}
};int main()
{People *p1 = new Man("xiaoMing");People *p2 = new Woman("xiaoHua");//交换vptrint *m = (int*)p1;int *w = (int*)p2;int tmp = m[0];m[0] = w[0];w[0] = tmp;p1->print_sex();p2->print_sex();delete p1;delete p2;return 0;
}
结果示例:
demo3:
成员方法调用在运行阶段确定,默认参数和访问权限在编译阶段(字面判断调用)确定
静态绑定时运行时确定,动态绑定时运行时确定
结构图:
代码示例:
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.28) #最低版本要求SET(CMAKE_CXX_COMPILER "g++-11") #设置g++编译器PROJECT(CLASS) #设置工程名MESSAGE(STATUS "CPP test") #打印消息ADD_EXECUTABLE(pro test.cpp) #生成可执行文件
run.sh
#!/bin/bashif [ -f ./Makefile ]
thenmake clean
ficmake .makeecho "---------------------------------"./prog++ test.cpp -o test -gobjdump -S test > test.dis
clean.sh
rm -rf CMakeCache.txt CMakeFiles Makefile cmake_install.cmake *.o pro test test.dis
test.cpp
#include <iostream>
#include <cstring>class C
{public:virtual void print_num(int num = 1){std::cout << "num:" << num << std::endl;}};class C1 : public C
{private:void print_num(int num = 2){std::cout << "num:" << num << std::endl;}
};class D
{public:D(){std::cout << "D()" << std::endl; clear();};void clear(){memset(this,0,sizeof(*this));}virtual void print_info(){std::cout << "D::print_info" << std::endl;}
};class D1 : public D
{public:D1(){std::cout << "D1()" << std::endl;}void print_info(){std::cout << "D1::print_info" << std::endl;}
};int main()
{//默认参数压栈在编译时完成(压入默认参数10),运行时调用函数执行(调用C1::print_num)//权限(public,proteated,private)是在编译时确定(字面判断调用)//静态绑定时运行时确定,动态绑定时运行时确定C *c = new C1();c->print_num();delete c;//基类构造和派生类构造时clear清理了调用基类构造的vptr,派生类构造未清理/** D *d = new D();* d->print_info();* delete d;*/D1 *d1 = new D1();d1->print_info();delete d1;return 0;
}
结果示例: