面向对对象就是把把问题和解决方法看成一个整体,称为对象。(解决问题的具体过程是一致的)
(仅记重点)
* 成员函数的定义和声明分开的方式
* 成员函数的存储方式
1. 成员函数不存在对象之内,这样每个对象都带有一段重复代码, 显然是浪费空间。
实际上,成员函数都存在代码区上, 这是个公共空间,每个对象调用时都是调这个函数, 但传递参数不同 , 下面this具体介绍。
2. 在有成员变量的时候,用sizeof计算对象或者类的大小, 成员函数不计入。
3. 在只有成员变量的时候,sizeof(类)的大小不为0, 为1, 原因是要留着占位1字节占位,大小为0的类的实例化对象无法存储。
4. 遵循struct的对其规则。
原因:某些硬件一次只能读一定大小的空间。
如下图, 最大对齐数是4, 如果按照上面的方式存储, 读取char很轻松,读取一次,去掉无用的三个字节,但是读取int就要读取两次 一个八字节,再去除无用的4字节。
而下面的存储方式读取两个数据都只需要读取一次,极大提升了效率。
* this指针
矛盾:上面将不同的对象调用相同的成员函数那结果岂不是一样?
原来,每当调用成员函数的时候,编译器会自动把对应对象的地址传给要调用的成员函数,
用this指针作为形参接收, 这个动作是隐式的, 但能在汇编中看到, 如图。
看起来第一个函数print()只传了两个参数,实际上传了3个参数。
第二个函数p()看起来没传参数,实际上传了1个参数。
*注意点
1. this指针的属性是(Datatype)* const , this不能修改,this指向的值可以修改。
2. 面试题
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
void show()
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
p->show();
return 0;
}
这里p->Print()会正常运行, 因为调成员函数的时候把p(nullptr)的地址传过去,但是没有解引用
p->show()把p(nullptr)传过去后用p->_a访问了_a,存在对空指针的访问。程序运行崩溃。