-
如何学习
C++
-
函数重载
-
说明
- 字符串解析就是,编译时加在函数后面达到唯一的新函数.
-
c++
源码struct Test{ int a; }; void show(Test t) { t.a++; } void show(int t) { t++; } int main() { }
-
解析
g++ test.cpp -g
-
objdump
反编译000000000040050d <_Z4show4Test>: struct Test{ int a; }; void show(Test t) { 40050d: 55 push %rbp 40050e: 48 89 e5 mov %rsp,%rbp 400511: 89 7d f0 mov %edi,-0x10(%rbp) t.a++; 400514: 8b 45 f0 mov -0x10(%rbp),%eax 400517: 83 c0 01 add $0x1,%eax 40051a: 89 45 f0 mov %eax,-0x10(%rbp) } 40051d: 5d pop %rbp 40051e: c3 retq 000000000040051f <_Z4showi>: void show(int t) { 40051f: 55 push %rbp 400520: 48 89 e5 mov %rsp,%rbp 400523: 89 7d fc mov %edi,-0x4(%rbp) t++; 400526: 83 45 fc 01 addl $0x1,-0x4(%rbp) } 40052a: 5d pop %rbp 40052b: c3 retq
show(Test)
编译后变成了_Z4show4Test
,_Z
表示加密方式,4
表示后面函数show
名字长度,4Test
表示参数长度.show(int)
编译后变成了_Z4showi
,_Z
表示加密方式,4
表示后面函数show
名字长度,i
表示参数.基本类型被编译器简化了.
-
重复定义
struct Test{ int a; }; void show(Test t) { } void show(int t) { } extern "C" void _Z4showi(void) { } int main() { }
- 编译报错,重复定义,因为
_Z4showi
和show(int)
的名字重复了.
- 编译报错,重复定义,因为
-
另类调用
[root@localhost temp]# g++ test.cpp -ldl -rdynamic [root@localhost temp]# ./a.out show int: 1 [root@localhost temp]# cat test.cpp #include<dlfcn.h> #include<iostream> struct Test{ int a; }; void show(Test t) { } void show(int t) { std::cout << "show int: " << t << std::endl; } int main() { void (*t)(int); *(void**)&t = dlsym(RTLD_DEFAULT,"_Z4showi"); t(1); }
-
-
成员函数
-
说明
- 成员函数就是某个类型特定的函数.
- 普通函数添加了一个函数名的前缀,作为专用的函数而已.
-
源代码
#include<dlfcn.h> #include<iostream> struct Test{ int a; Test(int s=0):a(s){} void show() { std::cout << "show int: " << a << std::endl; } }; int main() { Test t; t.show(); }
-
编译执行
[root@localhost temp]# g++ test.cpp -g [root@localhost temp]# ./a.out show int: 0
-
反编译
objdump -dS a.out
000000000040081d <main>: Test(int s=0):a(s){} void show() { std::cout << "show int: " << a << std::endl; } }; int main() { 40081d: 55 push %rbp 40081e: 48 89 e5 mov %rsp,%rbp 400821: 48 83 ec 10 sub $0x10,%rsp Test t; 400825: 48 8d 45 f0 lea -0x10(%rbp),%rax 400829: be 00 00 00 00 mov $0x0,%esi 40082e: 48 89 c7 mov %rax,%rdi 400831: e8 66 00 00 00 callq 40089c <_ZN4TestC1Ei> t.show(); 400836: 48 8d 45 f0 lea -0x10(%rbp),%rax 40083a: 48 89 c7 mov %rax,%rdi 40083d: e8 70 00 00 00 callq 4008b2 <_ZN4Test4showEv> } 400842: b8 00 00 00 00 mov $0x0,%eax 400847: c9 leaveq 400848: c3 retq
-
c
风格[root@localhost temp]# g++ test.cpp -ldl -rdynamic -g [root@localhost temp]# g++ test.cpp -ldl -rdynamic [root@localhost temp]# ./a.out show int: 0 show int: 2 [root@localhost temp]# cat test.cpp #include<dlfcn.h> #include<iostream> class Test{ public: int a; Test(int s=0):a(s){} void show() { std::cout << "show int: " << a << std::endl; } }; int main() { Test t; Test b(2); t.show(); void (*td)(Test*); *(void**)&td = dlsym(RTLD_DEFAULT,"_ZN4Test4showEv"); td(&b); }
- 可以看到,按照
C
风格调用成员函数同样可以成功.
- 可以看到,按照
-
-
命名空间
-
说明
- 命名空间就是将范围内的所有的变量和函数等,所有有关的都添加一个前缀.
-
命名空间的目的
- 减少全局命名的冲突,特别是大项目.
-
命名空间的扩张
- 两个的前缀都一样,声明了就可以用了.
- 编译器也会这样优先搜索.
-
源代码
[root@localhost temp]# g++ test.cpp [root@localhost temp]# cat test.cpp #include<dlfcn.h> #include<iostream> namespace cool { void show(int a) { std::cout << "cool,show: " << a << std::endl; } }; int main() { }
-
反编译
000000000040081d <_ZN4cool4showEi>:
N
表示命名空间,4cool
表示长度。
-
C
风格[root@localhost temp]# g++ test.cpp -ldl -rdynamic [root@localhost temp]# ./a.out cool,show: 2 [root@localhost temp]# cat test.cpp #include<dlfcn.h> #include<iostream> namespace cool { void show(int a) { std::cout << "cool,show: " << a << std::endl; } }; int main() { void (*td)(int); *(void**)&td = dlsym(RTLD_DEFAULT,"_ZN4cool4showEi"); td(2); }
-
-
匿名空间
-
总结