第三层:C++对象模型和this指针

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

文章目录

🎉welcome🎉
✒️博主介绍一名大一的智能制造专业学生在学习C/C++的路上会越走越远后面不定期更新有关C/C++语法数据结构算法Linuxue5使用制作游戏的心得和大家一起共同成长。
✈️C++专栏C++爬塔日记
😘博客制作不易👍点赞+⭐收藏+➕关注

前情回顾

上回说到在进入第二层之后我见识到了对象的初始化和清理封装的力量甚至只是为了给它打基础但是有惊无险我也成功掌握进入到了第三层…

C++对象模型和this指针

进入到第三层映入眼帘的是一块巨大的石碑石碑上密密麻麻的都是字和代码正当我还是迷惑这层的力量是什么的时候那道声音的主人仿佛看出了我的迷惑解释随之飘来“这层的力量是一种隐藏在编译器内的神秘力量对象模型和this指针它们两个相辅相成祝你好运闯关者…"

类成员变量和类成员函数的储存

在C++中类内的成员变量和成员函数是分开储存的只有类内的非静态成员变量才属于这个类的对象如下图所示。

在这里插入图片描述
那如果类内什么属性都没有这个类实体化的对象会占用内存空间吗

#include<iostream>
using namespace std;

class A
{

};
void test1()
{
	A a;
	cout << "对象a的大小是 " << sizeof(a) << endl;
}

int main()
{
	test1();
	return 0;
}

在这里插入图片描述
这是为什么类内明明没有成员变量为什么会占用大小新机子蛙一直摸你肚子对于C++的编译器而言每一个对象都应该有一个独一无二的地址当类内没有非静态成员变量时创建一个对象如果不给它一片空间在遇到这个对象的时候编译器不知道它开辟的内存空间在哪里如果这种空对象多那在未来里面加入非静态成员变量的时候可能就会产生几个空对象指向同一片空间出现错误。
当拥有一个非静态成员变量的时候对象的大小是多少是数据类型所占字节+1吗还是会产生对齐是数据类型的整数倍呢

#include<iostream>
using namespace std;

class A
{
	int a;
};
void test1()
{
	A a;
	cout << "对象a的大小是 " << sizeof(a) << endl;
}

int main()
{
	test1();
	return 0;
}

在这里插入图片描述
看到了是数据类型的大小当里面不是空的时候编译器就不会给对象这一个字节的大小来确定对象在内存空间中的位置直接用类内非静态成员变量的位置也变相的说明了非静态成员变量是属于类实例化出来的对象的。
那上面说静态成员变量不属于对象那现在也可以去验证一下。

#include<iostream>
using namespace std;

class A
{
	static int a;
};
void test1()
{
	A a;
	cout << "对象a的大小是 " << sizeof(a) << endl;
}

int main()
{
	test1();
	return 0;
}

在这里插入图片描述
又变成了1说明我们的静态成员变量是不属于对象的。
那非静态成语函数呢

#include<iostream>
using namespace std;

class A
{
public:
	void a()
	{

	}
};
void test1()
{
	A a;
	cout << "对象a的大小是 " << sizeof(a) << endl;
}

int main()
{
	test1();
	return 0;
}

在这里插入图片描述
根据这些可以得知只有非静态成员变量属于类实例化的对象类内属性和非静态成员函数是分开存放的静态成员函数也与非静态成员函数一样不属于类实例化的对象。

this指针

this指针概念

通过上面得知在C++中成员变量和成员函数是分开存放的每一个非静态成员函数都会产生一份函数实例也就是说多个同类型的对象在调用函数的会共用同一块空间那么问题就来了这同一个函数是通过上面来区分是哪个对象来调用函数的这里就C++就提供了一个特殊对象指针——this指针this指针它指向被调用的成员函数所属的对象它隐藏在每一个非静态成员函数内不需要程序员去定义可以直接使用假设现在有三个对象p1、p2、p3其中p1要调用函数其底层就如下图所示
在这里插入图片描述
就如同这样p1不能直接指向先指向this指针这个时候this指针代表了p1指向要调用的函数。

this指针用途

  1. 当成员函数的形参和成员变量名同名时可以用this指针来区分
  2. 在非静态成员函数中返回对象本身是可以使用return *this

用途1解释

当成员函数的形参和成员变量同名时这个时候如果要对成员变量在成员函数内进行一个赋值的操作时会失败的可以验证一下

#include<iostream>
using namespace std;

class A
{
public:
	void a(int b)
	{
		b = b;
	}
	int b;
};

void test1()
{
	A a;
	a.a(10);
	cout << a.b << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述
可以看到属性内b根本没有改变这是因为在编译器严重它认为函数内的b都是形参解决方法很简单在右侧的b前面加上this指针让this指针指向对象a中成员变量b的那块空间进行改变。

#include<iostream>
using namespace std;

class A
{
public:
	void a(int b)
	{
		this->b = b;
	}
	int b;
};

void test1()
{
	A a;
	a.a(10);
	cout << a.b << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

用途2解释

当对一个对象进行函数调用时这个时候想多调用几次除了使用循环还有没有别的方法试试下面这种看看行不行

  • 对象名.调用函数.调用函数.调用函数…

尝试使用一下

#include<iostream>
using namespace std;

class A
{
public:
	void a(int b)
	{
		this->b += b;
	}
	int b;
};

void test1()
{
	A a;
	a.b=0;
	a.a(10).a(10).a(10);
	cout << a.b << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述
可以看到报错报错为表达式必须具有类类型但它具有类型“void"这是这么回事呢我们看代码
在这里插入图片描述
成员函数的返回值为void所以类型不兼容那把返回类型换成类名呢

#include<iostream>
using namespace std;

class A
{
public:
	A a(int b)
	{
		this->b += b;
		return *this;
	}
	int b;
};

void test1()
{
	A a;
	a.b=0;
	a.a(10).a(10).a(10);
	cout << a.b << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

确实不会报错了但是调用了三次成员函数为什么结果是这样而不是30为什么要返回* this而不是this首先为什么是* this而不是this是因为this是指针它指向的是地址也就是对象a的那块空间*解引用找到的就是对象a结果第一次是10因为返回的类型是类名就会调用拷贝构造函数将数据重新放在一份新的空间而不是原空间所以这里要返回的值应该是引用

#include<iostream>
using namespace std;

class A
{
public:
	A& a(int b)
	{
		this->b += b;
		return *this;
	}
	int b;
};

void test1()
{
	A a;
	a.b = 0;
	int b = 10;
	a.a(b).a(b).a(b);
	cout << a.b << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

空指针调用成员函数

在创建对象的时候这个时候创建的对象是一个对象指针并且对这个指针置空那这个时候让它去访问成员函数会发生什么

#include<iostream>
using namespace std;

class A
{
public:
	void a()
	{
		cout << "调用函数a" << endl;
	}
	void b()
	{
		c = 10;
	}
	int c;
};
void test1()
{
	A* p = NULL;
	p->a();
	p->b();
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述
在调用时可以发现为什么只调用了a函数b函数为什么不能调用调试看一下
在这里插入图片描述
看到是在对非静态成员变量c赋值时产生的错误错误为this为空指针那这个给时候不难看出对于空指针只能调用部分函数这部分函数为不访问类内成员变量的函数而访问类内成员变量的函数则不能访问是因为this为空指针没有确定的对象所以访问不到类内的成员变量。那这个时候就可以优化一下函数用if或者assert来判断一下this指针是否为空可以大大提高函数的健壮性。

const修饰的成员变量

当一个程序员不想让木某个函数体内部修改成员的值时可以在函数后面跟一个const该函数内部就不能修改成员变量了

返回类型 函数参数 const
{
实现功能
}

在this指针中提到不管写不写this指针函数内都会调用this指针this指针属于指针常量不可以改变指向但可以改变指针的指向的值所以this指针的本质就是

  • 类名 * const this;

那这个时候程序员不仅仅让this指针不能改变指向也不能改变指向的值时就可以想上面一样加const函数本身也就变成常函数了这个时候函数内部就不能改变成员变量了如果在对象前加一个const那对象就变成常对象了也不能修改同时常对象只能调用常函数。

常函数内可以被修改的值

那有没有什么方法让常函数内也可以被修改这里就有一种特殊变量可以在常函数内进行修改只需要在成员变量前加上关键字mutable就可以在常函数内进行修改了。

突破步入第四层

“轰隆”一声巨响面前的巨大石碑轰然倒下通往下一层的楼梯也出现在眼前…

本章知识点图片形式

在这里插入图片描述

😘预知后事如何关注新专栏和我一起征服C++这座巨塔
🚀专栏C++爬塔日记
🙉都看到这里了留下你们的👍点赞+⭐收藏+📋评论吧🙉

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: c++