C++核心编程——4.3 C++对象模型和this指针

news2024/11/18 5:57:11

4.3.1 成员变量和成员函数分开存储

        在C++中,类内的成员变量和成员函数分开存储(虽然封装在一起,但是分开存储)

        只有非静态成员变量才属于类的对象上,静态成员(包括静态成员变量和静态成员函数)和非静态成员函数不属于类的对象上。

class Person {
public:
	Person() {
		mA = 0;
	}
	//非静态成员变量占对象空间(是属于类的对象上的,当类中只有一个int时,类就只占4个字节)
	int mA;
	//静态成员变量不占对象空间(不属于类的对象上,在类中不占用空间)
	static int mB; 
	//非静态成员函数也不占对象空间,所有函数共享一个函数实例(不属于类的对象上)
	void func() {
		cout << "mA:" << this->mA << endl;
	}
	//静态成员函数也不占对象空间
	static void sfunc() {
	}
};
int Person::mB = 10; //类内声明,类外初始化
int main() {

  //空对象(对象内为空)占用的内存空间为1个字节(用于区分两个对象,两个对象不能用一个空间)
  //C++编译器会为每一个对象也分配一个字节空间,是为了区分空对象占内存的位置
    
    
	cout << sizeof(Person) << endl; // 调用sizeof可以访问类的大小

	system("pause");

	return 0;
}

4.3.2 this指针概念

问题:

       C++中成员变量和成员函数是分开存储的,每一个非静态成员函数只会诞生一份函数实例(所以对象都在调用这一个函数),也就是多个同类型的对象会共用一块代码,那这一块代码是如何区分那个对象调用自己的呢?

解决方案:

c++通过提供特殊的对象指针,this指针,解决上述问题。

特点:this指针指向被调用的成员函数所属的对象

隐含在每一个非静态成员函数内

不需要定义,直接使用即可

用途:

  • 解决名称冲突:当形参和成员变量同名时,可用this指针来区分

如下图所示,红色框和蓝色框中各属于一份数据,用this指针进行区分,其中蓝色框为传入的形参,红色框为类中的成员变量。

  • 返回对象本身:在类的非静态成员函数中返回对象本身,可使用return *this(通过解引用解开该对象)

传入的是一个类,用引用的方式返回

Person& PersonAddPerson(Person p)

链式编程示例:

        其中,p2.PersonAddPerson(p1)执行后返回p2(在语法上p2.PersonAddPerson(p1) =p2),返回p2后又嵌套后面的.PersonAddPerson(p1)组合成p2.PersonAddPerson(p1),执行后再返回p2,以此类推不断嵌套;

 传入的是一个类,用值的方式返回

   Person PersonAddPerson1(Person p)
{
    this->age += p.age;  
	return *this; 
}

 注:用值的方式返回,在执行完成员函数后会创建新的对象(属性和原对象一模一样,但是已经不是原对象),再在新对象上进行操作。

上图的执行逻辑:

           首先,执行p5.PersonAddPerson(p4):

                  先执行成员函数(只是执行到this->age += p.age,还没有到return语句),原来的p5对象上的age会加上p4对象上的age(此时对象p5上的age是p5.age+p4.age);

                再执行return语句,会创建出和p5一模一样的对象(对象上的属性一致)p5',再将p5'进行返回(此时返回的已经不是原来的p5,后续的操作都和p5没有关系);

         其次,执行p5'.PersonAddPerson(p3):

                 先执行成员函数,p5'上的age加上p3的age;

                再执行return语句,创建p5''返回;

         然后,执行p5''.PersonAddPerson(p2):

                先执行成员函数,p5''上的age加上p2的age;

                再执行return语句,创建p5'''返回;

          ......

           可以无线嵌套,但是已经和原始的p5没有关系,原始的p5只会加上p4的age而已,输出的p5.age的结果只会是原始的p5.age+p4.age

class Person
{
public:

	Person(int age)
	{
//1、当形参和成员变量同名时,可用this指针来区分
        //this指针指向被调用的成员函数所属的对象
        
	     this->age = age;
	}
    
//2、返回对象本身
	Person& PersonAddPerson(Person p)  //传入的是一个类,以引用的方式进行返回
   
	{
		this->age += p.age;  //自身的年龄加上传入的年龄
		//返回对象本身
	return *this;  //当调用p2时,this是指向p2的指针,如果返回指针的解引用就是p2的本体
        //this是指向p2的指针,*this指向p2的本体
	}
    
   Person PersonAddPerson1(Person p)   //返回值,会创建新的对象,再在新的对象上操作
        {
		this->age += p.age;  //自身的年龄加上传入的年龄
		//返回对象本身
	return *this;  //当调用p2时,this是指向p2的指针,如果返回指针的解引用就是p2的本体
        //this是指向p2的指针,*this指向p2的本体
	     }

	int age;
};

void test01()
{
	Person p1(10);  
    //此时在调用p1(被调用的),所以this指针指向的是p1(被调用的成员函数)
	cout << "p1.age = " << p1.age << endl;

	Person p2(10);
   
    //如果函数执行完之后能返回函数的本身,就可以进行一个嵌套
    //即p2.PersonAddPerson(p1)执行后返回p2(p2.PersonAddPerson(p1) 相当于p2)
    //链式编程思想,可以无限的往后延申(同cout无线延申输出)
	p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);
    

    //把p1的age多加几次
	cout << "p2.age = " << p2.age << endl;
    
    Person p3(1);
    Person p4(2);
    Person p5(3);
    
    p5.PersonAddPerson1(p4).PersonAddPerson1(p3).PersonAddPerson1(p2);
    
    //每次执行会复制出一份一摸一样的,但是已经不是它本身
    
    cout << "p5.age = " << p5.age << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

4.3.3 空指针访问成员函数

C++允许空指针调用成员函数(只适用于成员函数中没有用到this指针)

如果用到this指针,需要加以判断保证代码的健壮性(判断指针为空则返回)

//空指针访问成员函数
class Person {
public:

	void ShowClassName() {
		cout << "Person类!" << endl;
	}

	void ShowPerson() {
		if (this == NULL) {
			return;
		}  //空指针直接返回就不会出错,提高健壮性(防止别人传空指针搞破坏)
		cout << mAge << endl;
 //实际上的表达是 cout << this-> mAge << endl 其中this本身为空,不可以访问里面的值
	}

public:
	int mAge;
};

void test01()
{
	Person * p = NULL;
	p->ShowClassName(); //空指针,可以调用成员函数(只适用于成员函数中没有用到this指针)
	p->ShowPerson();  //但是如果成员函数中用到了this指针,就不可以了
}

int main() {

	test01();

	system("pause");

	return 0;
}

4.3.4 const修饰成员函数

常函数常对象
定义成员函数后加const声明对象前加const
语法

void 成员函数名() const

{}

const 类名 对象名
特点常函数内不可以修改成员属性(指针指向和指针指向的值)常对象只能调用常函数
成员变量普通成员变量可访问不可修改
mutable修饰的成员变量可访问可修改

const修饰成员函数的区别见下表所示:

const修饰不用const修饰
语法

void 成员函数名() const

{}

void 成员函数名() 

{}

类似指针语法const 类名 * const this类名 * const this

const即修饰类,又修饰指针

const只修饰指针
this指针的指向不可修改
this指针指向的值不可修改可修改
class Person {
public:
	Person() {
		m_A = 10;
		m_B = 20;
	}
     
	
	//如果想让指针指向的值也不可以修改,需要声明常函数
	void ShowPerson() const{
		

		//this指针(隐含在每一个非静态成员函数内)的本质是一个指针常量,指针的指向不可修改
		//this == NULL;  //报错,调用是this指针已经指向p,不可以再修改指向(NULL)
//普通成员函数可访问不可修改		
	//成员函数不加const:Person * const this       指针指向不可修改指向的值可以修改
		//m_A = 100;        //声明前面不加const则this指向的值可以修改
		//this->m_A = 100; //this指针隐含在每一个非静态成员函数内,逻辑上同上一句
   //成员函数加const:const Person * const this   指针指向和指向的值都不可以修改
		//m_A = 100;        //this指针指向的对象的数据是补可以修改的
		//this->m_A = 100; //同上
		cout << this->m_A << endl;

//mutable修饰的变量可修改可访问
		cout << this->m_B << endl;
		this->m_B = 100;
		cout << this->m_B << endl;
		cout << "访问常函数" << endl;

	}

	void MyFunc()  {
		m_A = 100;
	}

public:
	int m_A ;
    mutable int m_B; //可修改 可变的
};


//const修饰对象  常对象
void test01() {

	Person p;
	p.ShowPerson();

	const Person person; //常对象(对象前面加const)
//普通对象可访问不可修改
	//person.m_A = 100; //常对象不允许修改普通的成员变量:常对象不能修改成员变量的值(不允许修改指针指向的值)
	cout << person.m_A << endl;
//mutable对象可访问可修改
	cout << person.m_B << endl;
	person.m_B = 50; //但是常对象可以修改mutable修饰成员变量
	cout << person.m_B << endl;

	常对象只能访问常函数
	//person.MyFunc(); //常对象不能调用普通的成员函数函数,因为普通成员函数可以修改属性,而常对象本身不能修改属性,已经违背了
	person.ShowPerson();
}

int main() {

	test01();

	system("pause");

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1614873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

绿联 安装qbittorrent及一些常见错误的解决办法

绿联 安装qbittorrent及一些常见错误的解决办法 1、镜像 linuxserver/qbittorrent:latest 2、安装 2.1、创建容器 按需决定是否进行资源限制。 2.2、基础设置 2.3、网络 桥接即可。 注&#xff1a;如果使用IPV6&#xff0c;请选择"host"模式。 注&#xff1a;如…

C# 使用 ThoughtWorks.QRCode 生成二维码

目录 关于 ThoughtWorks.QRCode 开发运行环境 方法设计 代码实现 调用示例 Logo图标透明化 小结 关于 ThoughtWorks.QRCode 二维码是用某种特定的几何图形按一定规律在平面分布的、黑白相间的、记录数据符号信息的图形&#xff0c;在应用程序开发中也被广泛使用&#x…

虚拟局域网PPTP配置与验证

虚拟局域网PPTP配置与验证 前言PPTP服务侧安装配置REF 前言 虚拟专用网&#xff08;Virtual Private Network&#xff0c;VPN&#xff09;是一种通过公共网络建立安全的连接的技术。它能够在不同的地理位置之间建立私密的通信通道&#xff0c;实现远程访问网络资源的安全性和隐…

c语言不难说C语言难的,已经说明你根本不适合计算机编程工作

对普通人来说C语言是学习编程的最佳入门语言&#xff0c;有效培养你的编程思维&#xff0c;你有了这个基础后去学其它语言&#xff0c;你会惊讶地发现原来其它语言原来这么好学&#xff0c;现在出现一个Python说小白最适合&#xff0c;在开始前我有一些资料&#xff0c;是我根据…

真实世界的密码学(一)

原文&#xff1a;annas-archive.org/md5/655c944001312f47533514408a1a919a 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 前言 序言 当你拿起这本书时&#xff0c;你可能会想&#xff0c;为什么又一本关于密码学的书&#xff1f;甚至&#xff0c;为什么我要读这本…

STM32G030F6P6TR ST意法

STM32G030F6P6TR是ST(意法半导体)一款基于高性能ArmCortex-M032位RISC内核&#xff0c;工作频率高达64MHz的32位MCU微控制器。代理销售ST(意法半导体)全系列IC电子元器件-中芯巨能为您提供STM32G030F6P6TR(ST 32位MCU)引脚图及中文参数介绍等内容。 STM32G030F6P6TR的中文参数 …

UE5(基础动作)多人游戏制作蹲伏

1.创建输入操作&#xff0c;IA_Crouch 在输入映射中添加 IA_Crouch,在触发器中创建两个索引&#xff0c;已按下已松开来创建蹲伏输入。 蹲伏操作必须要勾选角色-角色移动-crouch勾选可蹲伏否则你的人物无法真正蹲下。 为蹲伏创建函数&#xff0c;创建布尔来判断是否蹲伏。 通过…

Linux 网络操作命令FTP

FTP命令 引言 文件传输协议&#xff08;FTP&#xff09;是一种用于在网络上进行文件传输的协议。在Linux系统中&#xff0c;FTP可以作为一个非常有用的工具来上传、下载和管理文件。本文将介绍如何在Linux系统中安装FTP服务器&#xff0c;以及如何使用FTP客户端进行文件传输。…

什么是XXE攻击?如何进行防护

安全性很难做到正确&#xff0c;即使在当今具有安全意识的世界中&#xff0c;也存在一些严重的漏洞&#xff0c;例如 XML 外部实体 (XXE)&#xff0c;它们被忽视并最终成为破坏的原因。 XML 外部实体 (XXE) 攻击是一种计算机安全漏洞&#xff0c;通常存在于 Web 应用程序中&…

贪心 | | 将数组和减半的最少操作数

目录 将数组和减半的最少操作数 除 2 将数组和减半的最少操作数 2208. 将数组和减半的最少操作次数 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/minimum-operations-to-halve-array-sum/description/ 由题意可知&#xff0c;我们可以遍历数组&…

高斯过程回归【详细数学推导】

机器学习笔记 第一章 机器学习简介 第二章 感知机 第三章 支持向量机 第四章 朴素贝叶斯分类器 第五章 Logistic回归 第六章 线性回归和岭回归 第七章 多层感知机与反向传播【Python实例】 第八章 主成分分析【PCA降维】 第九章 隐马尔可夫模型 第十章 奇异值分解 第十一章 熵…

[移动通讯]【无线感知-P1】[从菲涅尔区模型到CSI模型-3][Mobius transformations-3]

前言&#xff1a; 参考 Professor Bonfert-Taylors 《Mobius transformations》&#xff0c;我们重点理解 因此莫比乌斯变换是共形映射&#xff08; conformal mappinngs &#xff09;以及反演特性inversion 目录 mobious transfromation 定义 mobious transfromation 性质…

掌握item_get_app,提升电商推广转化率

一、引言 在数字化时代&#xff0c;电商行业蓬勃发展&#xff0c;竞争也日趋激烈。为了提高销售额和用户满意度&#xff0c;电商企业需要不断探索新的推广策略和技术手段。其中&#xff0c;掌握item_get_app技术&#xff0c;对于提升电商推广转化率具有重要意义。本文将深入探…

FreeRTOS之中断管理

1.中断简介&#xff1a; 2.中断优先级分组&#xff1a; 注意&#xff0c;中断优先级数值越低&#xff0c;其优先级越高。而在任务优先级数值越高&#xff0c;其优先级越大。 3.中断相关寄存器介绍&#xff1a; 4.系统中断优先级设置&#xff1a; FreeRTOS管理中断的两个函数&am…

屏幕太小?教你如何轻松将苹果电脑投射到安卓电视!

好几个人开组会&#xff0c;一台电脑怎么够看&#xff1f;那岂不是要好几颗脑袋挤在一起盯着屏幕&#xff1f;如果能将电脑屏幕投屏到大电视上&#xff0c;视觉就没有压力了。 将电脑屏幕投射到电视上&#xff0c;不仅能够让观众更加集中注意力&#xff0c;还能让信息的传递更加…

基于PyAutoGUI图片定位的自动化截图工具--完成了

1、计划 压测完成后需要编写性能测试报告&#xff0c;报告中所需数据截图较多&#xff0c;使用自动化操作方便快捷&#xff0c;就编写一个界面工具以便后续复用。 基于PyAutoGUI图片定位的自动化截图工具–jmeter部分 基于PyAutoGUI图片定位的自动化截图工具–jmeter部分&#…

Linux命令接着学习

which命令&#xff0c;找到各种命令程序所处在的位置 语法&#xff1a;which查找的命令 那么对于我们想查找其他类型文件所在的位置&#xff0c;我们可以用到find命令 find命令 选项为-name&#xff0c;表示按照文件名进行查找 find命令中通配符 find命令和前面rm命令一样&…

2024/4/21周报

文章目录 摘要Abstract文献阅读题目问题贡献方法卷积及池化层LSTM层CNN-LSTM模型 数据集参数设置评估指标实验结果 深度学习使用GRU和LSTM进行时间预测1.库的导入&数据集2.数据预处理3.模型定义4.训练过程5.模型训练 总结 摘要 本周阅读了一篇基于CNN-LSTM黄金价格时间序列…

数据结构与算法笔记:线性建堆

ACM大牛带你玩转算法与数据结构-课程资料 本笔记属于船说系列课程之一&#xff0c;课程链接&#xff1a; 哔哩哔哩_bilibilihttps://www.bilibili.com/cheese/play/ep66799?csourceprivate_space_class_null&spm_id_from333.999.0.0 你也可以选择购买『船说系列课程-年度会…

IBM SPSS Statistics for Mac:强大的数据分析软件

IBM SPSS Statistics for Mac是一款功能强大的数据分析软件&#xff0c;专为Mac用户设计&#xff0c;提供了一系列专业的统计分析和数据管理功能。无论是科研人员、数据分析师还是学生&#xff0c;都能从中获得高效、准确的数据分析支持。 IBM SPSS Statistics for Mac v27.0.1…