这个a的大小是12,并没有算成员函数的大小
按我们开始想的那样,岂不是每次实例化个对象里面都存储着成员变量和成员函数,那样花费太大了,那成员函数在哪里,实际上他在常量区,C++叫代码段。这里的代码段并不是指我们所编写的代码,是我们所写的代码转换成指令,我们编的代码本质上属于文件,存储在硬盘当中。
那假如成员函数,成员变量都没有或者只有成员函数大小是多少呢?0吗?
这种类叫空类,它实际留了一个字节作为占位,实例化对象后表示对象存在
前面可知成员函数是在公共的代码段,那么编译器是怎么区别是谁调用的Init函数呢?
是d1.init(x,x,x); d2.init(x,x,x);
区分的吗?
不是的,假如成员变量是public,上述代码和d1.month,d2.month不一样,后者的意思是调用d1,d2对象内的month。
而d1.init(x,x,x); d2.init(x,x,x);
指的是到这个d1,d2是Data类,到类中寻找存储在代码段的成员方法。
本质上d1.init(x,x,x); d2.init(x,x,x);
等价于 call Init(地址)
这两个相同是怎么区分的呢?
其实是C++编译器给每一个非静态的成员函数增加了一个隐藏的指针参数,这个指针指向了调用该成员函数的对象,成员函数内部对该对象成员变量进行操作都是由这个指针进行操作,只不过对用户透明,编译器自动完成。
而且自己不能手动加Data* this,是编译器自动加好的。所以我们可以用他,实际也用了只是不显示,只是这里把他写出来。
d1.init(x,x,x);d2.init(x,x,x);
会分别打印出d1,d2对象的地址。
这两道题有助于我们更好地了解this指针
面试题1:
this指针存在哪里?
this指针是个形参,按理说应该存在栈中,但是通过反汇编看到,形参从右向左push入栈,第四个参数this指针存到了寄存器中。
面试题2:
this指针可以为NULL吗?
像之前我们定义的是
A p;
p.print(); 而p.print()传的实参实际上是p.print(&p),
定义有个隐藏的形参是 p.print(A* this)
所以this形参接收的是实参&p,也就是他的地址
而在下图p是一个类指针。就表示地址。所以this直接就接收的是p(类比上面代码)。
说明清楚后把上面的问题分成两个子问题,下面这段代码会崩溃吗?
p是一个类指针,与调用成员变量意思不同,p->PrintA();
的意思是到A这个类中去寻找存储在代码段中的成员方法。上面说到这个由于他是个类指针,所以直接传的是p,
p->PrintA(A* this);
接收到p, 所以this变成了nullptr,这个函数里调用了成员变量_a
cout<<_a<<endl;等价于cout<<this._a<<endl
而this是nullptr此时对空指针进行了操作就会崩溃。
再看另一个子问题。