C++对象模型与this指针

news/2024/5/4 8:18:01/文章来源:https://blog.csdn.net/qq_24472227/article/details/129970708

一、成员变量与成员函数分开存储

1、在C++中,类内的成员变量和成员函数分开存储

首先,对于一个空对象,占用内存空间为1

class person
{};void test01()
{person p;cout << sizeof(p) << endl;
}

 因为C++编译器给每个空对象分配1个字节空间,防止不同空对象占用同一块内存空间,便于区分


2、只有非静态成员变量属于类的对象上

 在person类中加入一个非静态成员变量

class person
{int m_a; // 非静态成员变量,属于类的对象上
};void test02()
{person p;cout << sizeof(p) << endl;
}

 再加上静态成员变量

再加上非静态成员函数

最后加上静态成员函数 

 

 总结:只有非静态成员变量才属于类的对象上


二、this指针

概念:上一节中我们知道成员变量与成员函数分开存储,每一个非静态成员函数只会产生一份函数实例,也就是多个同类型的对象共用一块代码,而如何区分究竟是哪个对象调用自己,用到this指针

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

性质:

①this指针是隐含在每一个非静态成员函数内的一种指针

②this指针不需要定义,可以直接使用

作用:

①当形参与成员变量同名时,可用this指针加以区分

举例说明:我们先创建类person和测试函数test01,在类内创建属性m_age,函数person,形参age

class person
{
public:person(int age){m_age = age;}int m_age;
};
void test01()
{person p(20);cout << p.m_age << endl;
}

此时可正常输出

但是,如果我们将属性m_age改为age得到这个

class person
{
public:person(int age){age = age;}int age;
};
void test01()
{person p(20);cout << p.age << endl;
}

同颜色的即为同一个age,无法正常输出

在此基础上,我们在函数内加上this指针

class person
{
public:person(int age){this->age = age; // 加上this->}int age;
};

 可以发现3个age是同源的。此时,this就代表p,this->age == p.age;


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

class person
{
public:person(int age){this->age = age;}void personAdd(person& p) // 函数本体age加上参数P的age{this->age += p.age;}int age;
};
void test02()
{person p1(10);cout << p1.age << endl;person p2(10);cout << p2.age << endl;
}

 

 而如果我们想要多次加和

void test02()
{p2.personAdd(p1);cout << p2.age << endl;p2.personAdd(p1).personAdd(p1).personAdd(p1); // 想要多次加和cout << p2.age << endl;
}

要先修改函数体返回值

person& personAdd(person& p) // 而且要引用{this->age += p.age;return *this; // 返回对象本身}

而如果函数体返回值不使用引用&,则无法修改值, 

 因为这样修改完第一次p2后,返回的是另一个变量,并且后面第2次开始修改的都是另一个变量,再另一个变量


三、空指针访问成员函数

C++中空指针也可以调用成员函数,不过要注意是否用到this指针

如果遇到this指针,加上判断,防止代码出错

class person
{
public:void show_name(){cout << "Joyce" << endl;}void show_age(){cout << this->m_age << endl;}int m_age;};
void test01()
{person* p = NULL;p->show_age(); // 非法访问p->show_name();
}

对于这段代码,指针p为NULL,调用show_name函数时可以正常输出,因为她只是简单的打印特定的内容,而调用show_age函数时将报错,因为函数内this->m_age;调用了this指针的m_age,而this指针为NULL,造成非法访问

因此,我们在函数内部加上判断

void show_age(){if (this == NULL){return;}cout << this->m_age << endl;}

以此便可以防止代码为NULL时出错


四、const修饰成员函数

常函数:

①成员函数后加const称该函数为成员函数

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

③成员属性声明时加关键字mutable,在常函数中仍然能修改


接下来创建person类与函数show_name;

class person
{
public:void show_name(){this->m_a = 100; // 非 常对象,可修改this = NULL;// this指针的指向不可修改}int m_a;
};

 因为this指针本质是一个指针常量,所以其指向(地址)不可修改,但其指向的值可以修改

本质:person * const this;


不过,如果在函数加上const,则地址与值都不可修改

本质:const person *const this;

 不过,如果在常函数中的属性的声明前加上mutable,则可以修改

class person
{
public:void show_name() const // 这里有const{this->m_a = 100; //可修改}mutable int m_a; // 加上const
};

常对象:

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

②常对象只能调用常函数


class person
{
public:void show_name() const{this->m_a = 100; }mutable int m_a;int m_b;
};
void test02()
{person p;p.m_b = 20; 
}

此时test02内可以修改m_b;接下来在p前加上const使其变成常对象

void test02()
{const person p;p.m_b = 20; // 不可修改p.m_a = 20; // 可修改
}

则m_b不可修改,而m_a由于前面加了mutable,可以修改


同时,在person类中我们再创建一个普通函数func,尝试在test函数中调用刚才的常函数和普通函数

class person
{
public:void show_name() const // 常函数{this->m_a = 100; }void func() // 普通函数{;}mutable int m_a;int m_b;
};void test02()
{const person p; // 创建常对象p.show_name(); // 常函数p.func(); // 普通函数
}

 无法调用,因为常对象只能调用常函数(因为普通函数可以修改属性)

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

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

相关文章

【juc】wait和notify原理

目录一、monitor锁结构图二、说明一、monitor锁结构图 二、说明 1.线程1一开始持有对象A的monitor锁&#xff0c;即monitor中的owner指向线程1 2.线程1在执行的过程中发现条件a不满足执行不下去了&#xff0c;此时线程1可以调用wait方法&#xff0c;那么线程1就进入waitset进行…

【RabbitMQ高级篇】消息可靠性问题(1)

目录 1.消息可靠性 1.1.生产者消息确认 1.1.1.修改配置 1.1.2.定义Return回调 1.1.3.定义ConfirmCallback 1.2.消息持久化 1.2.1.交换机持久化 1.2.2.队列持久化 1.2.3.消息持久化 1.3.消费者消息确认 1.3.1.演示none模式 1.3.2.演示auto模式 1.4.消费失败重试机制…

.net C#反编译及脱壳常用工具--小结

1、Reflector --微软自家工具--推荐 Reflector是最为流行的.Net反编译工具。Reflector是由微软员工Lutz Roeder编写的免费程序。Reflector的出现使NET程序员眼前豁然开朗&#xff0c;因为这个免费工具可以将NET程序集中的中间语言反编译成C#或者Visual Basic代码。除了能将IL转…

五、页面切割技术,实现工作台

页面切割技术 1.<frameset>和<frame> <frameset>:用来切割页面 <frameset cols"20%,60%,20%"> 竖着把窗口切三部分 <frameset rows"20%,60%,20%"> 横着把窗口切三部分 <frame>&#xff1a;用来显示页面 <frame …

三星公司因ChatGPT造成数据泄露?

作者丨黑蛋 ChatGPT大家最近应该都听过很多&#xff0c;关于各种ChatGPT消息铺天盖地&#xff0c;将会取代大部分人工&#xff0c;ChatGPT代替创作&#xff0c;绘画&#xff0c;很多公司因此裁员等消息多不胜数&#xff0c;甚至短短几个月&#xff0c;ChatGPT升级版ChatGPT4就…

无需服务器免费上线你的静态网页

无需服务器免费上线你的静态网页:https://s.qiniu.com/bmaYJf

Keil 5 安装教程及简单使用【嵌入式系统】

Keil 5 安装教程【嵌入式系统】前言推荐说明keil5安装教程第一阶段&#xff1a;安装mdk第二阶段&#xff1a;激活mdk第三阶段&#xff1a;安装STM32芯片包第四阶段&#xff1a;安装C51单片机第五阶段&#xff1a;激活C51单片机keil 5的简单使用1建立新工程2创建新文件3.生成HEX…

华硕 ASUS-PRIME-B560M-A Intel Core i5-11400黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板ASUS-PRIME-B560M-A 处理器Intel Core i5-11400已驱动 内存16GB DDR4 3200 Mhz已驱动 硬盘Western Digital Black SN750 500GB已驱动 显卡SAPPH…

社区团购是什么?打破传统消费模式的新选择

社区团购作为一种新兴的消费模式&#xff0c;已经成为了越来越多人的选择。在社区团购中&#xff0c;商家可以通过团购的方式向消费者提供优惠的价格和服务&#xff0c;同时也可以借助社区团购来扩大销售渠道和提高品牌知名度。本文将以一家小型便利店的社区团购为例&#xff0…

艾瑞巴蒂看过来!OSSChat 上线:融合 CVP,试用通道已开放

还在纠结于反复查找开源项目的技术文档&#xff1f; 团队常因频繁搜索开源项目主页导致效率低下&#xff1f; 每天都要问一遍【开源项目中那些“小白问题”究竟有没有更快的解决方法&#xff1f;】 对此&#xff0c;只想对你说&#xff1a;赶紧试试 OSSChat&#xff01;赶紧试…

灵动MM32 MindSPIN系列MCU —— 无刷电机驱动的得力伙伴

无论是在工业应用&#xff0c;还是智能家居和物联网应用上&#xff0c;提高效率和节能减碳一直为其主轴诉求&#xff0c;而有着兼顾于高效与节能特色的直流无刷电机&#xff0c;正是符合此应用的主流。 灵动微电子MindSPIN系列MCU产品就是针对直流无刷电机驱动所量身打造的。由…

Leetcode.112 路径总和

题目链接 Leetcode.112 路径总和 easy 题目描述 给你二叉树的根节点 root和一个表示目标和的整数 targetSum。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum。如果存在&#xff0c;返回 true&#xff1b;否则&#xf…

自学编程的5大误区,早知道早避坑,过来人的宝贵经验

前言 有的人自学很快&#xff0c;几乎一个多月就能掌握一门技术&#xff0c;而有的人苦苦坚持&#xff0c;最后还是半途而废&#xff0c;很大的原因就在于在学习的时候掉进了一些误区没能走出来。 今天我们就来讲讲自学编程常见的5大误区&#xff0c;避开这些误区我们定能在自…

美团全国各配送站机房配备深圳钡铼技术工业物联网监测终端S270,实现远程数据监测

美团集团与钡铼技术&#xff0c;日前签约美团旗下全国各配送站机房监测项目。深圳钡铼技术为美团每家配送站机房配备工业物联网数据监测终端S270&#xff0c;接入美团系统&#xff0c;助力美团集团实现物联网升级。实现远程采集仓库机房水浸、温湿度、烟感、停电报警等数据&…

“成年人”的数据库,既要又要也要!

欢迎访问 OceanBase 官网获取更多信息&#xff1a;https://www.oceanbase.com/ 3 月 25 日&#xff0c;第一届 OceanBase 开发者大会在北京举行&#xff0c;《明说三人行》访谈栏目创始人兼主持人卢东明、沃趣科技创始人兼 CEO 陈栋、DBAplus 社群联合创始人杨建荣、PostgreSQL…

强化学习——初探强化学习

本文引自&#xff1a;《 动手学强化学习 》 第 1 章 初探强化学习 1.1 简介 亲爱的读者&#xff0c;欢迎来到强化学习的世界。初探强化学习&#xff0c;你是否充满了好奇和期待呢&#xff1f;我们想说&#xff0c;首先感谢你的选择&#xff0c;学习本书不仅能够帮助你理解强…

MATLAB插值函数interp1

MATLAB插值函数interp1 参考链接&#xff1a;interp1 插值法又称“内插法”&#xff0c;是利用函数f (x)在某区间中已知的若干点的函数值&#xff0c;作出适当的特定函数&#xff0c;在区间的其他点上用这特定函数的值作为函数f (x)的近似值&#xff0c;这种方法称为插值法。…

【C语言】浮点数和0比较

文章目录一. 浮点数存储时是有精度损失的二. 浮点数不能直接进行 比较三. 使用精度来比较两个浮点数是否相等四. 浮点数和0比较一. 浮点数存储时是有精度损失的 下面程序中我们打印一个浮点数的值 int main() {double d 3.6;printf("%.50f\n", d);return 0; }观察…

已解决IndexError: arrays used as indices must be of integer (or boolean) type

已解决IndexError: arrays used as indices must be of integer (or boolean) type 文章目录报错问题解决方法PS报错问题 之前在工作中遇到过这个坑&#xff0c;记录一下问题以及解决方法&#xff0c;不一定针对所有情况都能用&#xff0c;但是可以供大家参考。 问题描述如下&…

前端正确处理“文字溢出”的思路

前言&#xff1a; 最近在项目中需要做到类似于 Mac 下这种&#xff0c;当屏幕宽度足以容下当前文件名称的时候&#xff0c;文件名称全部展示&#xff0c;不做省略。 然而当用户缩放浏览器显示的尺寸时&#xff0c;我们需要做到省略中间的文字&#xff0c;选择保留后缀这种方案…