本文主要探讨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/bash
if [ -f ./Makefile ]
then
make clean
fi
cmake .
make
echo "---------------------------------"
./pro
g++ test.cpp -o test -g
objdump -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-64
Disassembly of section .init:
0000000000001000 <_init>:
1000: f3 0f 1e fa endbr64
1004: 48 83 ec 08 sub $0x8,%rsp
1008: 48 8b 05 e1 2f 00 00 mov 0x2fe1(%rip),%rax # 3ff0 <__gmon_start__@Base>
100f: 48 85 c0 test %rax,%rax
1012: 74 02 je 1016 <_init+0x16>
1014: ff d0 call *%rax
1016: 48 83 c4 08 add $0x8,%rsp
101a: c3 ret
Disassembly 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 endbr64
1034: 68 00 00 00 00 push $0x0
1039: e9 e2 ff ff ff jmp 1020 <_init+0x20>
103e: 66 90 xchg %ax,%ax
1040: f3 0f 1e fa endbr64
1044: 68 01 00 00 00 push $0x1
1049: e9 d2 ff ff ff jmp 1020 <_init+0x20>
104e: 66 90 xchg %ax,%ax
1050: f3 0f 1e fa endbr64
1054: 68 02 00 00 00 push $0x2
1059: e9 c2 ff ff ff jmp 1020 <_init+0x20>
105e: 66 90 xchg %ax,%ax
Disassembly of section .plt.got:
0000000000001060 <__cxa_finalize@plt>:
1060: f3 0f 1e fa endbr64
1064: 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 endbr64
1074: 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 endbr64
1084: 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 endbr64
1094: 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 endbr64
10a4: 31 ed xor %ebp,%ebp
10a6: 49 89 d1 mov %rdx,%r9
10a9: 5e pop %rsi
10aa: 48 89 e2 mov %rsp,%rdx
10ad: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
10b1: 50 push %rax
10b2: 54 push %rsp
10b3: 45 31 c0 xor %r8d,%r8d
10b6: 31 c9 xor %ecx,%ecx
10b8: 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 hlt
10c6: 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,%rax
10e1: 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,%rax
10ed: 74 09 je 10f8 <deregister_tm_clones+0x28>
10ef: ff e0 jmp *%rax
10f1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
10f8: c3 ret
10f9: 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,%rsi
1111: 48 89 f0 mov %rsi,%rax
1114: 48 c1 ee 3f shr $0x3f,%rsi
1118: 48 c1 f8 03 sar $0x3,%rax
111c: 48 01 c6 add %rax,%rsi
111f: 48 d1 fe sar $1,%rsi
1122: 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,%rax
112e: 74 08 je 1138 <register_tm_clones+0x38>
1130: ff e0 jmp *%rax
1132: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
1138: c3 ret
1139: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001140 <__do_global_dtors_aux>:
1140: f3 0f 1e fa endbr64
1144: 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 %rbp
114e: 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,%rbp
1159: 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 %rbp
1174: c3 ret
1175: 0f 1f 00 nopl (%rax)
1178: c3 ret
1179: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001180 <frame_dummy>:
1180: f3 0f 1e fa endbr64
1184: e9 77 ff ff ff jmp 1100 <register_tm_clones>
0000000000001189 <main>:
func();
}
};
int main()
{
1189: f3 0f 1e fa endbr64
118d: 55 push %rbp
118e: 48 89 e5 mov %rsp,%rbp
1191: 48 83 ec 50 sub $0x50,%rsp
1195: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
119c: 00 00
119e: 48 89 45 f8 mov %rax,-0x8(%rbp)
11a2: 31 c0 xor %eax,%eax
C 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),%rax
11be: 48 89 c7 mov %rax,%rdi
11c1: e8 d8 00 00 00 call 129e <_ZN1C4funcEv>
c1.func();
11c6: 48 8d 45 bf lea -0x41(%rbp),%rax
11ca: 48 89 c7 mov %rax,%rdi
11cd: e8 0a 01 00 00 call 12dc <_ZN2C14funcEv>
c2.func();
11d2: 48 8d 45 c0 lea -0x40(%rbp),%rax
11d6: 48 89 c7 mov %rax,%rdi
11d9: e8 3c 01 00 00 call 131a <_ZN2C24funcEv>
c3.func();
11de: 48 8d 45 c8 lea -0x38(%rbp),%rax
11e2: 48 89 c7 mov %rax,%rdi
11e5: e8 6e 01 00 00 call 1358 <_ZN2C34funcEv>
C *pc = &c1;
11ea: 48 8d 45 bf lea -0x41(%rbp),%rax
11ee: 48 89 45 d8 mov %rax,-0x28(%rbp)
pc->func(); //静态绑定(编译时确定)
11f2: 48 8b 45 d8 mov -0x28(%rbp),%rax
11f6: 48 89 c7 mov %rax,%rdi
11f9: e8 a0 00 00 00 call 129e <_ZN1C4funcEv>
C2 *pc2 = &c3;
11fe: 48 8d 45 c8 lea -0x38(%rbp),%rax
1202: 48 89 45 e0 mov %rax,-0x20(%rbp)
pc2->func(); //动态绑定(运行时确定)
1206: 48 8b 45 e0 mov -0x20(%rbp),%rax
120a: 48 8b 00 mov (%rax),%rax
120d: 48 8b 10 mov (%rax),%rdx
1210: 48 8b 45 e0 mov -0x20(%rbp),%rax
1214: 48 89 c7 mov %rax,%rdi
1217: ff d2 call *%rdx
pc = &c; //静态绑定(编译时确定)
1219: 48 8d 45 be lea -0x42(%rbp),%rax
121d: 48 89 45 d8 mov %rax,-0x28(%rbp)
pc->func();
1221: 48 8b 45 d8 mov -0x28(%rbp),%rax
1225: 48 89 c7 mov %rax,%rdi
1228: e8 71 00 00 00 call 129e <_ZN1C4funcEv>
C1 *pc1 = &c1; //静态绑定(编译时确定)
122d: 48 8d 45 bf lea -0x41(%rbp),%rax
1231: 48 89 45 e8 mov %rax,-0x18(%rbp)
pc1->func();
1235: 48 8b 45 e8 mov -0x18(%rbp),%rax
1239: 48 89 c7 mov %rax,%rdi
123c: e8 9b 00 00 00 call 12dc <_ZN2C14funcEv>
pc2 = &c2; //动态绑定(运行时确定)
1241: 48 8d 45 c0 lea -0x40(%rbp),%rax
1245: 48 89 45 e0 mov %rax,-0x20(%rbp)
pc2->func();
1249: 48 8b 45 e0 mov -0x20(%rbp),%rax
124d: 48 8b 00 mov (%rax),%rax
1250: 48 8b 10 mov (%rax),%rdx
1253: 48 8b 45 e0 mov -0x20(%rbp),%rax
1257: 48 89 c7 mov %rax,%rdi
125a: ff d2 call *%rdx
C3 *pc3 = &c3;
125c: 48 8d 45 c8 lea -0x38(%rbp),%rax
1260: 48 89 45 f0 mov %rax,-0x10(%rbp)
pc3->func(); //动态绑定(运行时确定)
1264: 48 8b 45 f0 mov -0x10(%rbp),%rax
1268: 48 8b 00 mov (%rax),%rax
126b: 48 8b 10 mov (%rax),%rdx
126e: 48 8b 45 f0 mov -0x10(%rbp),%rax
1272: 48 89 c7 mov %rax,%rdi
1275: ff d2 call *%rdx
C4 c4; //定义在构造函数中的虚函数为静态绑定(编译时确定)
1277: 48 8d 45 d0 lea -0x30(%rbp),%rax
127b: 48 89 c7 mov %rax,%rdi
127e: 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),%rdx
128c: 64 48 2b 14 25 28 00 sub %fs:0x28,%rdx
1293: 00 00
1295: 74 05 je 129c <main+0x113>
1297: e8 f4 fd ff ff call 1090 <__stack_chk_fail@plt>
129c: c9 leave
129d: c3 ret
000000000000129e <_ZN1C4funcEv>:
void func()
129e: f3 0f 1e fa endbr64
12a2: 55 push %rbp
12a3: 48 89 e5 mov %rsp,%rbp
12a6: 48 83 ec 10 sub $0x10,%rsp
12aa: 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,%rsi
12b8: 48 8d 05 81 2d 00 00 lea 0x2d81(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>
12bf: 48 89 c7 mov %rax,%rdi
12c2: 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,%rsi
12d1: 48 89 c7 mov %rax,%rdi
12d4: e8 a7 fd ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>
}
12d9: 90 nop
12da: c9 leave
12db: c3 ret
00000000000012dc <_ZN2C14funcEv>:
void func()
12dc: f3 0f 1e fa endbr64
12e0: 55 push %rbp
12e1: 48 89 e5 mov %rsp,%rbp
12e4: 48 83 ec 10 sub $0x10,%rsp
12e8: 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,%rsi
12f6: 48 8d 05 43 2d 00 00 lea 0x2d43(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>
12fd: 48 89 c7 mov %rax,%rdi
1300: 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,%rsi
130f: 48 89 c7 mov %rax,%rdi
1312: e8 69 fd ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>
}
1317: 90 nop
1318: c9 leave
1319: c3 ret
000000000000131a <_ZN2C24funcEv>:
virtual void func()
131a: f3 0f 1e fa endbr64
131e: 55 push %rbp
131f: 48 89 e5 mov %rsp,%rbp
1322: 48 83 ec 10 sub $0x10,%rsp
1326: 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,%rsi
1334: 48 8d 05 05 2d 00 00 lea 0x2d05(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>
133b: 48 89 c7 mov %rax,%rdi
133e: 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,%rsi
134d: 48 89 c7 mov %rax,%rdi
1350: e8 2b fd ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>
}
1355: 90 nop
1356: c9 leave
1357: c3 ret
0000000000001358 <_ZN2C34funcEv>:
void func()
1358: f3 0f 1e fa endbr64
135c: 55 push %rbp
135d: 48 89 e5 mov %rsp,%rbp
1360: 48 83 ec 10 sub $0x10,%rsp
1364: 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,%rsi
1372: 48 8d 05 c7 2c 00 00 lea 0x2cc7(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>
1379: 48 89 c7 mov %rax,%rdi
137c: 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,%rsi
138b: 48 89 c7 mov %rax,%rdi
138e: e8 ed fc ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>
}
1393: 90 nop
1394: c9 leave
1395: c3 ret
0000000000001396 <_ZN2C44funcEv>:
virtual void func()
1396: f3 0f 1e fa endbr64
139a: 55 push %rbp
139b: 48 89 e5 mov %rsp,%rbp
139e: 48 83 ec 10 sub $0x10,%rsp
13a2: 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,%rsi
13b0: 48 8d 05 89 2c 00 00 lea 0x2c89(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>
13b7: 48 89 c7 mov %rax,%rdi
13ba: 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,%rsi
13c9: 48 89 c7 mov %rax,%rdi
13cc: e8 af fc ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>
}
13d1: 90 nop
13d2: c9 leave
13d3: c3 ret
00000000000013d4 <_ZN2C4C1Ev>:
C4()
13d4: f3 0f 1e fa endbr64
13d8: 55 push %rbp
13d9: 48 89 e5 mov %rsp,%rbp
13dc: 48 83 ec 10 sub $0x10,%rsp
13e0: 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),%rax
13ef: 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,%rsi
13fc: 48 8d 05 3d 2c 00 00 lea 0x2c3d(%rip),%rax # 4040 <_ZSt4cout@GLIBCXX_3.4>
1403: 48 89 c7 mov %rax,%rdi
1406: 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,%rsi
1415: 48 89 c7 mov %rax,%rdi
1418: e8 63 fc ff ff call 1080 <_ZNSolsEPFRSoS_E@plt>
func();
141d: 48 8b 45 f8 mov -0x8(%rbp),%rax
1421: 48 89 c7 mov %rax,%rdi
1424: e8 6d ff ff ff call 1396 <_ZN2C44funcEv>
}
1429: 90 nop
142a: c9 leave
142b: c3 ret
Disassembly of section .fini:
000000000000142c <_fini>:
142c: f3 0f 1e fa endbr64
1430: 48 83 ec 08 sub $0x8,%rsp
1434: 48 83 c4 08 add $0x8,%rsp
1438: 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/bash
if [ -f ./Makefile ]
then
make clean
fi
cmake .
make
echo "---------------------------------"
./pro
g++ test.cpp -o test -g
objdump -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");
//交换vptr
int *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/bash
if [ -f ./Makefile ]
then
make clean
fi
cmake .
make
echo "---------------------------------"
./pro
g++ test.cpp -o test -g
objdump -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;
}
结果示例:


被折叠的 条评论
为什么被折叠?



