4.3 C++对象模型和this指针

4.3 C++对象模型和this指针

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

在C++中,类内的成员变量和成员函数分开存储
只有非静态成员变量才属于类的对象上

#include <iostream>class Person {
public:Person() {mA = 0;} //非静态成员变量占对象空间int mA;//静态成员变量不占对象空间static int mB;//函数也不占对象空间,所有函数共享一个函数实例void func() {std::cout << "mA:" << this->mA << std::endl;} //静态成员函数也不占对象空间static void sfunc() {}
};int main() {//实例化一个对象为p1Person p1;std::cout << "Person:"<<sizeof(Person) << std::endl;std::cout << "p1:" << sizeof(p1) << std::endl;return 0;
}

运行结果如下:

image-20231220115319320

4.3.2 this指针概念

通过4.3.1我们知道在C++中成员变量和成员函数是分开存储的
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
那么问题是:这一块代码是如何区分那个对象调用自己的呢?
c++通过提供特殊的对象指针,this指针,解决上述问题。

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

this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可

this指针是一个常量指针,可以看做const type * this ,指针的指向不能修改,this = NULL这样是错的。

this指针的用途:

当形参和成员变量同名时,可用this指针来区分

在类的非静态成员函数中返回对象本身,可使用return *this

#include <iostream>class Person {
public:Person(int age) {//1 使用this区分形参和成员变量this->age = age;} Person& PersonAddPerson(Person p) {this->age += p.age;//2 返回对象本身,this为指针,所以加上*return *this;} //定义一个成员变量,属性为publicint age;
};void test01()
{   //实例化一个对象为p1,会调用有参构造函数Person p1(10);//打印p1.age的结果std::cout << "p1.age:" << p1.age << std::endl;//实例化一个对象为p2Person p2(12);//p2.PersonAddPerson(p1)这是使用p2对象调用成员函数PersonAddPerson(p1),//成员函数返回值是对象p2,然后再次调用成员函数p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);std::cout << "p2.age:" << p2.age << std::endl;}int main() {test01();return 0;
}

运行结果如下:

image-20231220122148474

#include <iostream>class MyClass {
public:void printAddress() {std::cout << "Address of the current object: " << this << std::endl;}void modifyObject() {// 下面的语句是非法的,会导致编译错误// this = nullptr;  // Error: assignment of read-only parameter 'this'// 修改成员变量是合法的data = 42;}private:int data;
};int main() {MyClass obj;// 调用成员函数,显示对象地址obj.printAddress();// 调用修改对象的函数obj.modifyObject();return 0;
}
4.3.3 空指针访问成员函数

C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
如果用到this指针,需要加以判断保证代码的健壮性

示例:

#include <iostream>class Person {
public:void ShowClassName() {std::cout << "Person类" << std::endl;} void ShowPerson() {if(this == NULL)return ;std::cout << "age:" << age << std::endl;} int age;};void test01()
{   //创建一个对象指针Person* p1 = NULL;//使用对象指针调用成员函数p1->ShowClassName();//使用对象指针调用成员函数,成员函数使用了this指针,空对象指针就使用不了   p1->ShowPerson();}int main() {test01();return 0;
}

执行结果如下:

image-20231220131818347

成员函数去掉this判断部分

#include <iostream>class Person {
public:void ShowClassName() {std::cout << "Person类" << std::endl;} void ShowPerson() {/*if(this == NULL)return ;*/std::cout << "age:" << age << std::endl;} int age;};void test01()
{   //创建一个对象指针Person* p1 = NULL;//使用对象指针调用成员函数p1->ShowClassName();//使用对象指针调用成员函数,成员函数使用了this指针,空对象指针就使用不了p1->ShowPerson();}int main() {test01();return 0;
}

再次编译执行结果如下

image-20231220132755137

对于上面出现的错误做一个解释,

代码中,如果去掉了 if(this == NULL) 的检查,并试图在一个空指针上调用 ShowPerson 函数,程序会尝试通过一个空指针来访问 age 成员变量。对空指针进行解引用是一种未定义的行为,通常会导致段错误。

具体步骤如下:

  1. 声明一个空指针,例如 Person* nullPointer = nullptr;
  2. 尝试在这个空指针上调用一个成员函数:nullPointer->ShowPerson();
  3. ShowPerson 函数内部,尝试通过 this->age 访问 age 成员变量。
  4. 由于 this 是一个空指针,尝试访问 this->age 会导致段错误。
4.3.4 const修饰成员函数

常函数:

成员函数后加const后我们称为这个函数为常函数

常函数内不可以修改成员属性

成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象:

声明对象前加const称该对象为常对象

常对象只能调用常函数

const修饰成员函数

#include <iostream>class Person {
public://默认构造函数Person() {p_a = 0;p_b = 0;} void ShowPerson() {//隐含在每个成员函数内部都有一个this指针,this是一个常量指针//this = NULL; 常量指针的内容不能修改this->p_a = 10;//对于常量指针的指向的内容可以修改       } void ShowPerson2() const {//隐含在每个成员函数内部都有一个this指针,this是一个常量指针//this = NULL; 常量指针的内容不能修改//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量//this->p_a = 20;//p_b变量被mutable修饰,可以修改this->p_b = 100;//常函数中变量不能修改//p_a = 12;//使用mutable修改的变量可以修改p_b = 22;       } public:int p_a;mutable int p_b;};void test01()
{   //创建一个对象,会调用默认构造函数Person p1;//查看变量p_a和p_b的值,调用构造函数后值都为0std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;//使用对象调用成员函数p1.ShowPerson();//查看此时变量p_a和p_b的值,p_a会变为10,p_b为0std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;//使用对象调用常量成员函数p1.ShowPerson2();//查看此时变量p_a和p_b的值,p_a会为10,p_b为22std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;}int main() {test01();return 0;
}

运行结果如下图:

image-20231220151754139

const修饰对象

#include <iostream>class Person {
public://默认构造函数Person() {p_a = 0;p_b = 0;} void ShowPerson() {//隐含在每个成员函数内部都有一个this指针,this是一个常量指针//this = NULL; 常量指针的内容不能修改this->p_a = 10;//对于常量指针的指向的内容可以修改       } void ShowPerson2() const {//隐含在每个成员函数内部都有一个this指针,this是一个常量指针//this = NULL; 常量指针的内容不能修改//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量//this->p_a = 20;//p_b变量被mutable修饰,可以修改this->p_b = 100;//常函数中变量不能修改//p_a = 12;//使用mutable修改的变量可以修改p_b = 22;       } public:int p_a;mutable int p_b;};void test01()
{   //创建一个常量对象p1,会调用默认构造函数const Person p1;//1 常量对象不能修改成员变量的值//p1.p_a = 33;//可以修改被mutable修饰的变量值p1.p_b = 11;//可以访问成员变量的值std::cout << "p_a:" << p1.p_a << std::endl;std::cout << "p_b:" << p1.p_b << std::endl;//2 常量对象访问成员函数,只能访问常函数//ShowPerson是非常函数,常量对象不能访问//p1.ShowPerson();//访问常函数p1.ShowPerson2();std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;}int main() {test01();return 0;
}

运行结果如下:

image-20231220161615196

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

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

相关文章

数据预处理:多重共线性_检测和解决办法

文章目录 1.多重共线性简介&#xff08;Collinearity and Multicollinearity&#xff09;1.1 多重共线性的后果1.2 处理多重共线性问题的方法 2. 设置2.1 导入库2.2 数据集特征波士顿房价BMI 数据集 2.3 导入数据 3. 相关矩阵3.1 聚类图 4. 方差膨胀因子4.1 两种多重共线性4.2 …

外卖托管运营专家邦火策划怎么样,为您的餐厅带来了什么不同?

在当今激烈竞争的餐饮市场&#xff0c;外卖托管运营正逐渐成为许多餐厅提升业绩的有效手段。邦火策划以其专业的服务和独特的策略&#xff0c;成为外卖托管运营领域的专家。让我们一同探究&#xff0c;选择邦火策划为您的餐厅带来了怎样的不同。 在邦火策划的引领下&#xff0…

【UML】第10篇 类图(属性、操作和接口)(2/3)

目录 3.3 类的属性&#xff08;Attribute&#xff09; 3.3.1 可见性&#xff08;Visibility&#xff09; 3.3.2 属性的名称 3.3.3 数据类型 3.3.4 初始值 3.3.5 属性字符串 3.4 类的操作&#xff08;Operations&#xff09; 3.4.1 参数表 3.4.2 返回类型 3.5 类的职责…

基于JavaWeb的个人健康信息管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本个人健康信息管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据…

data数据响应式

data数据响应式 所有在实例上挂载的属性&#xff0c;都可以在视图中直接使用 data中的数据&#xff0c;是经过“数据劫持”的&#xff0c;是“响应式数据” 响应式&#xff1a;修改数据&#xff0c;视图会自动更新 MV原理&#xff1a;其中一条线的原理&#xff0c;data响应式的…

Nessus详细安装-windows (保姆级教程)

Nessus描述 Nessus 是一款广泛使用的网络漏洞扫描工具。它由 Tenable Network Security 公司开发&#xff0c;旨在帮助组织评估其计算机系统和网络的安全性。 Nessus 可以执行自动化的漏洞扫描&#xff0c;通过扫描目标系统、识别和评估可能存在的安全漏洞和弱点。它可以检测…

DRF从入门到精通三(反序列化数据校验源码分析、断言Assert、DRF之请求、响应)

文章目录 一、反序列化数据校验源码分析二、断言Assert三、DRF之请求、响应Request类和Response类请求中的Request 能够解析前端传入的编码格式响应中的Response能够响应的编码格式 一、反序列化数据校验源码分析 反序列化数据校验&#xff0c;校验顺序为&#xff1a;先校验字段…

Go后端开发 -- Golang的语言特性

Go后端开发 – Golang的语言特性 文章目录 Go后端开发 -- Golang的语言特性一、Golang的优势1.部署极其简单&#xff1a;2.静态语言3.语言层面的并发4.强大的标准库5.简单易学6.运行效率对比 二、Golang的适用领域1.应用领域2.明星产品 三、Golang的不足 一、Golang的优势 1.部…

共享购:消费前沿的领导者

在当今这个信息化、互联网高速发展的时代&#xff0c;商业模式也在不断地创新和变革。共享购模式作为一种新型的商业模式&#xff0c;正逐渐受到广泛的关注和追捧。本文将深入探讨共享购模式的核心理念、优势以及如何应用在实际商业场景中&#xff0c;为读者揭示这一模式的巨大…

计算机组成原理综合5

A 按照题意&#xff0c;程序P执行的时钟周期数为1000080%11000020%1028000&#xff0c;程序P的平均CPI为28000/100002.8&#xff0c;计算机主频为1GHz&#xff0c;CPU执行时间为28000/(1G/s)28μs。 B A 符号位为1 首先将0.4375转化为二进制&#xff0c;0.250.1250.06250.43…

nodejs+vue+ElementUi资源互助共享平台的设计

后台&#xff1a;管理员功能有个人中心&#xff0c;用户管理&#xff0c;卖家管理&#xff0c;咨询师管理&#xff0c;萌宝信息管理&#xff0c;幼儿知识管理&#xff0c;保姆推荐管理&#xff0c;音频资源管理&#xff0c;二手商品管理&#xff0c;商品分类管理&#xff0c;资…

推荐给前端开发的 5 款 Chrome 扩展

工欲善其事&#xff0c;必先利其器。Chrome 可能是前端开发中使用最多的浏览器。在日常开发中&#xff0c;下列几款 Chrome 扩展也许能让你的开发工作事半功倍 &#x1f680; Vue.js devtools ⚙️ vue 官方专为 vue 应用开发的调试工具。 通过使用它&#xff0c;你可以快速查看…

力扣单调栈算法专题训练

目录 1 专题说明2 训练 1 专题说明 本博客用来计算力扣上的单调栈题目、解题思路和代码。 单调栈题目记录&#xff1a; 2232866美丽塔II 2 训练 题目1&#xff1a;2866美丽塔II。 解题思路&#xff1a;先计算出prefix[i]&#xff0c;表示0~i满足递增情况下&#xff0c;0~i…

NC65 查询单据所处的流程状态以及流程平台客户端工具类

1、查询单据所处的流程状态 nc.bs.wfengine.engine.EngineService的queryFlowStatus()方法 /*** 查询单据所处的流程状态* * param billId* param billType* param result* return* throws DbException*/public int queryFlowStatus(String billId, String billType, int flo…

【UML】第8篇 用例图(3/3)

目录 一、用例的关系 1.1 泛化&#xff08;Generalization&#xff09;关系 1.2 包含&#xff08;include&#xff09;关系 1.3 扩展关系 二、用例表示例 不是非要把电影改成连续剧&#xff0c;给大家播&#xff0c;确实是时间和精力有限。 用例图&#xff0c;虽然简单&…

荣誉 | 第七在线(7thonline)荣获STIF2023年度数智化创新典范奖

12月15日&#xff0c;STIF2023 第四届国际科创节暨 DSC2023 国际数字服务大会&#xff08;数服会&#xff09;在北京隆重举行。 在本届科创节暨数服会活动评选中&#xff0c;经企业申报、评委会审议&#xff0c;第七在线&#xff08;7thonline&#xff09;AI智能零售商品计划库…

什么是集成测试?它和系统测试的区别是什么? 操作方法来了

01 什么是集成测试&#xff1f; 集成测试是软件测试的一种方法&#xff0c;用于测试不同的软件模块之间的交互和协作是否正常。集成测试的主要目的是确保不同的软件模块能够无缝协作&#xff0c;形成一个完整的软件系统&#xff0c;并且能够满足系统的需求和规格。 在集成测试…

【3D生成与重建】SSDNeRF:单阶段Diffusion NeRF的三维生成和重建

系列文章目录 题目&#xff1a;Single-Stage Diffusion NeRF: A Unified Approach to 3D Generation and Reconstruction 论文&#xff1a;https://arxiv.org/pdf/2304.06714.pdf 任务&#xff1a;无条件3D生成&#xff08;如从噪音中&#xff0c;生成不同的车等&#xff09;、…

[C++]模板进阶

目录 C模板进阶&#xff1a;&#xff1a; 非类型模板参数 模板的特化 函数模板特化 类模板特化 全特化 偏特化 模板的分离编译 模板总结 C模板进阶&#xff1a;&#xff1a; 非类型模板参数 模板参数可分为类型形参和非类型形参。 类型形参&#xff1a;出现在参数列表中&am…

浅谈Redis分布式锁(上)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 不论面试还是实际工作中…