探秘C++机制的实现
作者:网络转载 发布时间:[ 2013/4/11 10:19:27 ] 推荐标签:
我曾经自学过C++,现在回想起来,当时是什么都不懂。说不上能使用C++,倒是被C++牵着鼻子走了。高中搞NOIP并不允许使用STL库,比赛中C++面向对象的机制基本没有什么用武之地,所以高中搞NOIP名为用C++,其实是c加上了cout和cin。
前几天看韩老师的《老码识途》,里面记录了一些C++面向对象机制的探索,又勾起了我的兴趣。而这个学期自学了汇编,又给了我自己动手探索提供了能力基础,自己上手以后,从一个更加底层的视角看C++机制的实现,让我在黑暗中摸到了驯服C++的缰绳。
引用:
本质上是指针,这一点即使大家没有看反汇编应该也是猜到了。
对象在内存上的布局:
1: class Father
2: {
3: int iA_;
4: int iB_;
5:
6: void FuncA();
7: void FuncB();
8: };
9:
10: class Child : Father
11: {
12: int iC_;
13: void FuncC();
14: };
一个Father对象里只包含 (低地址 –> 高地址) : iA_,iB_。也是一个Father对象的大小是8个字节,函数并不会占用内存空间。
为什么不会?
其实类的成员函数可以看做本质上与普通函数相同。
编译器在编译的时候知道函数的位置,所以调用普通函数的时候会直接 call 函数地址(偏移)。也是被硬编码了,函数的地址是固定的( 不考虑重定位之类的情况 )。
而成员函数的调用也是如此,只是编译器还多做了一件事情,是判断这个对象有没有调用这个函数的“权限”(函数不是你声明的,当然无权调用),“权限”不够会报错,告诉那个对象类型没有这个方法。
所以,类对象的大小与这个类的方法数多少是没关系的。成员函数和普通函数本质上一样,实现这个机制,要靠编译器来做工作。
this指针:
成员函数与普通函数不同之处之一是访问对象的数据。
要访问一个对象的元素,说白了是要找到这个元素所在的内存位置,也是要有指针。
我们没有看到传递this指针,因为这件事又是编译器帮我们做了。
反汇编会看到对象调用一个方法的时候,会将这个对象的首部地址赋值给ecx寄存器,通过寄存器来传递this指针。
我们在成员函数里可以不需明写this指针地调用对象元素,还是因为编译器帮我们多做了一步“翻译”。
私有化:
不多说,是编译器在编译阶段通过源码来判断某个元素是不是能够被访问,某个方法是不是能够被调用,运行的时候并不会有访问限制。看代码:
1: #include <stdio.h>
2:
3: class Exp
4: {
5: int iA_;
6: int iB_;
7:
8: public:
9: Exp()
10: {
11: iA_ = iB_ = 0;
12: }
13: void Out()
14: {
15: printf("%d %d
",iA_,iB_);
16: }
17: };
18:
19: int main()
20: {
21: Exp oA;
22: void *pC = &oA;
23:
24: oA.Out();
25: *(int*)pC = 1;
26: *(int*)((int)pC+4) = 2;
27: oA.Out();
28:
29: return 0;
30: }
结果是: 0 0
1 2
虽然 iA_,iB_是私有的,但是还是被外界修改了。因为编译器无法知道我干了这事(显式的 oA.iA_ = 1 被发现了哈)
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11