cpp_04_类_对象_this指针_常对象_常(成员)函数
1 类
1.1 类的定义
类的作用是抽象事物(抽取事物特征)的规则。
类的外化表现是用户自定义的复合数据类型(包括成员变量、成员函数):
成员变量用于表达事物的属性,成员函数用于表达事物的行为。
类的表现力远比基本类型强大很多。
结构体(类) 和 变量(对象):
// clsbase_pre.cpp 结构体(类) 和 变量(对象)
#include <iostream>
#include <cstring>
using namespace std;
// 类: 抽取事物特征的规则
struct Human {int m_age;char m_name[256];
};
int main( void ) {Human h; // 申请内存空间(对象)h.m_age = 22;strcpy( h.m_name, "张飞" );cout << "姓名: " << h.m_name << ", 年龄: " << h.m_age << endl;return 0;
}
1.2 类的一般形式:

// clsbase.cpp 结构体(类) 和 变量(对象)
#include <iostream>
#include <cstring>
using namespace std;
// 类: 抽取事物特征的规则
// struct
class Human {
public:void setinfo( int age=0, const char* name="无名" ) { // 桥梁函数if( !strcmp(name, "小二") ) {cout << "你才二呢" << endl;return;}m_age = age;strcpy( m_name, name ); }void getinfo( ) {cout << "姓名:" << m_name << ", 年龄:" << m_age << endl;}
private: int m_age;char m_name[256];
};
// 以上代码模拟类的设计者(标准库的类,第三方提供的类,自己设计的类)
// ------------------------
// 以下代码模拟类的使用者
int main( void ) {Human h; // 定义h (给h分配内存空间)// 在h所占据的内存空间中 定义m_age(给m_age分配内存空间),初值随机数// 在h所占据的内存空间中 定义m_name(给m_name分配内存空间),初值随机数cout << "h的大小:" << sizeof(h) << endl; // 260h.setinfo( 22,"张飞" ); h.setinfo( 22,"小二" ); h.getinfo();
// h.m_age = 22;
// strcpy( h.m_name, "张飞" );
// strcpy( h.m_name, "小二" );
// cout << "姓名: " << h.m_name << ", 年龄: " << h.m_age << endl;return 0;
}
1.3 访问控制限定符

public: 公有成员,类自己、子类、外部可以访问--谁都可以访问。
protected: 保护成员,类自己和子类可以访问。
private: 私有成员,类自己可以访问。
在C++中,类(class)和结构(struct)已没有本质性的差别,唯一不同:
类的缺省访问控制限定为私有(private);
结构的缺省访问控制限定为共有(public)。
访问控制限定符仅作用于类,而非作用于对象。
对不同成员的访问控制限定加以区分,体现了C++作为面向对象程序设计语言的封装特性。
类是现实世界的抽象,对象是类在虚拟世界的实例。
2 对象
对象的创建过程如下图。

3 成员函数形参--this
3.1 this指针理论

同一个类的不同对象各自拥有各自独立 的 成员变量。
同一个类的不同对象彼此共享同一份 成员函数。
在成员函数内部,通过this指针,来区分所访问的成员变量隶属于哪个对象。
(除静态成员函数外)类的每个成员函数,都有一个隐藏的指针型形参,名为this
this形参指向调用该成员函数的对象,一般称为this指针。
(除静态成员函数外)在类的成员函数内部,对所有成员的访问,都是通过this指针进行的。
// this.cpp 成员函数的形参 -- this
#include <iostream>
#include <cstring>
using namespace std;
// 当前程序中有两个对象(h/h2),每个对象中各有一份成员变量(m_age/m_name)共有两份成员变量,
// 成员函数只有一份
class Human {
public:void setinfo( /* Human* this */ int age=0, const char* name="无名" ) { // _ZN5Human7setinfoEiPKcthis->m_age = age;strcpy( this->m_name, name ); }void getinfo( /* Human* this */ ) { // _ZN5Human7getinfoEvcout << "姓名:" << this->m_name << ", 年龄:" << this->m_age << endl;}
private: int m_age;char m_name[256];
};
// 以上代码模拟类的设计者(标准库的类,第三方提供的类,自己设计的类)
// ------------------------
// 以下代码模拟类的使用者
int main( void ) {Human h; // 定义h (给h分配内存空间)// 在h所占据的内存空间中 定义m_age(给m_age分配内存空间),初值随机数// 在h所占据的内存空间中 定义m_name(给m_name分配内存空间),初值随机数cout << "h的大小:" << sizeof(h) << endl; // 260h.setinfo( 22,"zhangfei" ); // _ZN5Human7setinfoEiPKc( &h, 22, "zhangfei" )h.getinfo(); // _ZN5Human7getinfoEv( &h )Human h2; // 定义h2 (给h2分配内存空间)// 在h2所占据的内存空间中 定义m_age(给m_age分配内存空间),初值随机数// 在h2所占据的内存空间中 定义m_name(给m_name分配内存空间),初值随机数cout << "h2的大小:" << sizeof(h2) << endl;h2.setinfo( 20, "zhaoyun" ); // _ZN5Human7setinfoEiPKc( &h2, 20, "zhaoyun")h2.getinfo(); // _ZN5Human7getinfoEv( &h2 )return 0;
}
3.2 this指针的应用
1)有时为了方便,将类的成员变量与该类成员函数的参数取相同标识符(不好的编程习惯),这时在成员函数内部,必须用this指针将二者加以区分。
2)返回基于this指针的自引用,以支持串联调用。
多数情况下,程序员并不需要显示地使用this指针。
// hastothis.cpp 必须自己写this的情况
#include <iostream>
using namespace std;
class Integer {
public:void setinfo( /* Integer* this */ int i ) {this->i = i; // (1)必须自己写this}void getinfo( /* Integer* this */ ) {cout << /*this->*/i << endl; // 编译器补this}Integer& increment( /* Integer* this */ ) {++/*this->*/i; // 编译器补thisreturn *this; // 返回基于this指针的自引用 (2)必须自己写this}
private:int i;
};
// 以上代码模拟类的设计者(标准库的类,第三方提供的类,自己设计的类)
// ------------------------
// 以下代码模拟类的使用者
int main( void ) {Integer ix;ix.setinfo(1000);ix.getinfo();ix.increment().increment().increment(); // 串联调用ix.getinfo();return 0;
}
4 常对象和常函数
4.1 常对象
被const关键字修饰的对象、对象指针、对象引用,统称为常对象:
const User user;
const User* cptr = &user;
const User& cref = user;
(1)在定义常对象时必须初始化;
(2)常对象的成员属性不能进行更新;
(3)常对象不能调用该对象中非常成员函数【非const函数】,否则系统会报错误。
目的:
防止非const成员函数修改常对象中的成员属性的值,因为const成员函数是不
可以修改对象中成员属性的值。
(4)常对象的主要作用是【防止对常对象的成员属性的值进行修改】。
4.2 常(成员)函数
常函数 全称为 常成员函数。
普通成员函数才可能有常属性,变为常成员函数,即常函数。
在类成员函数的形参表之后,函数体之前加上const关键字,则该成员函数的this指针即具有常属性,这样的成员函数被称为常函数:
class 类名 {
返回类型 函数名 (形参表) const {
函数体;
}
};
原型相同的成员函数,常版本和非常版本构成重载
非常对象优先选择非常版本,如果没有非常版本,也能选择常版本;
常对象只能选择常版本。
在常函数内部无法修改成员变量的值,除非该成员变量被mutable关键字修饰。(编译器会做去常转换,见下列代码。)
// usethis.cpp
// 常对象(被const修饰的对象、指针、引用) 和 非常对象(没有被const修饰的对象、指针、引用)
// 常函数(编译器补的this参数有const修饰) 和 非常函数(编译器补的this参数没有const修饰)
#include <iostream>
using namespace std;
class Integer {
public:void setinfo( /* Integer* this */ int i ) { // 非常函数m_i = i; }void getinfo( /* Integer* this */ ) { // 非常函数cout << "非常函数getinfo: " << m_i << endl; }void getinfo( /* const Integer* this */ ) const { // 常函数const_cast<Integer*>(this)->m_i = 8888;cout << "常函数getinfo: " << m_i << endl;}
private:/*mutable*/ int m_i;
};
// 以上代码模拟类的设计者(标准库的类,第三方提供的类,自己设计的类)
// ------------------------
// 以下代码模拟类的使用者
int main( void ) {Integer ix; // ix是非常对象ix.setinfo(1000);ix.getinfo(); // getinfo(&ix)-->实参为Integer* 非常对象优先选择非常函数,也可选择常函数const Integer cix = ix; // cix是常对象cix.getinfo(); // getinfo(&cix)-->实参为const Integer* 常对象只能选择常函数,不能选择非常函数Integer* pix = &ix; // pix是非常对象Integer& rix = ix; // rix是非常对象pix->getinfo(); // getinfo(pix)-->实参为Integer*rix.getinfo(); // getinfo(&rix)-->实参为Integer*const Integer* pcix = &cix; // pcix是常对象const Integer& rcix = cix; // rcix是对象pcix->getinfo(); // getinfo(pcix)-->实参为const Integer*rcix.getinfo(); // getinfo(&rcix)-->实参为const Integer*return 0;
}
注意:
1)普通成员函数才有常函数。C++中构造函数,静态成员函数,析构函数,全局成员函数都不能是常成员函数。
>构造成员函数的用途是对对象初始化,成员函数主要是用来被对象调用的,如果构造
函数被设置成const,就不能更改成员变量,失去了其作为构造函数的意义。
>同理析构函数要释放成员所以也不能声明常函数。
>全局成员函数和静态成员函数static其函数体内部没有this指针,所以也不能是常成员
函数。
2)常函数中的this指针是常指针,不能在常成员函数中通过this指针修改成员变量的值。
3)非const对象可以调用常函数,也能调用非常函数。但是常对象只能调用常函数,不能调用非常函数(常对象也包括常指针和常引用)。
4)函数名和形参表相同的常函数和非常函数构成重载关系,此时,常对象调用常函数,非常对象调用非常函数。

练习题答案:
// TwoDimensional.cpp 设计一个二维坐标系的 类
#include <iostream>
using namespace std;class TwoDimensional {
public:void setinfo( int x, int y ) {m_x = x;m_y = y;}void getinfo( /* TwoDimensional* this */ ) { // 非常函数cout << "横坐标: " << m_x << ", 纵坐标: " << m_y << endl;}void getinfo( /* const TwoDimensional* this */ ) const { // 常函数cout << "横坐标: " << m_x << ", 纵坐标: " << m_y << endl;}
private:int m_x; // 横坐标int m_y; // 纵坐标
};int main( void ) {TwoDimensional a; // 非常对象a.setinfo( 100, 300 );a.getinfo( );const TwoDimensional ca = a; // ca是常对象ca.getinfo( );return 0;
}

相关文章:
cpp_04_类_对象_this指针_常对象_常(成员)函数
1 类 1.1 类的定义 类的作用是抽象事物(抽取事物特征)的规则。 类的外化表现是用户自定义的复合数据类型(包括成员变量、成员函数): 成员变量用于表达事物的属性,成员函数用于表达事物的行为。 类的表现…...
AttributeError: module ‘_winapi‘ has no attribute ‘SYNCHRONIZE‘解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
多媒体互动橱窗设计如何改变内容展示形式?
橱窗设计在展品展示中扮演着举足轻重的角色,它相较于传统展示形式,能更直观地呈现展品效果,而且优质的橱窗设计还能提升品牌的产品形象,正因此,也被广泛应用于企业、博物馆、店铺等场所。随着多媒体技术的蓬勃发展和行…...
flutter自定义地图Marker完美展示图片
世人都说雪景美 寒风冻脚无人疼 只道是一身正气 结论 参考Flutter集成高德地图并添加自定义Maker先实现自定义Marker。如果自定义Marker中用到了图片,那么会碰到图片没有被绘制到Marker的问题,此时需要通过precacheImage来预加载图片,从而解…...
no module named cv2 、numpy 、xxx超全解决方案
常规解决方案可见博客: https://blog.csdn.net/ALiLiLiYa/article/details/126988014 案例 上述仍没有解决,可以参考如下进行: 例如:明明文件夹存在下述文件,仍然报错。那么可能缺少环境变量导致。 No module named …...
BSWM 模式管理(二)ESH
BSWM 模式管理 ESH 1 ECU State Handling (ESH)2 BSWM ESH 五大模式与六大通用状态机3 状态机对应的切换条件 conditions or rules4 默认主要的 ACTION 或者 ACTION LIST1 ECU State Handling (ESH) 与 ECUM 相关,整个 ECU 状态管理的状态机制 2 BSWM ESH 五大模式与六大通…...
mac电脑安装虚拟机教程
1、准备一台虚拟机,安装CentOS7 常用的虚拟化软件有两种: VirtualBoxVMware 这里我们使用VirtualBox来安装虚拟机,下载地址:Downloads – Oracle VM VirtualBox 001 点击安装 002 报错:he installer has detected an…...
手动配置 kafka 用户密码,认证方式等的方式
场景 部分场景会指定使用某一kafka 来提高安全性,这里就不得不使用用户密码认证方式等来控制 方法示例 // 手动加载配置信息private Map<String, Object> consumerConfigs() {Map<String, Object> props new HashMap<>();props.put(ConsumerCo…...
机器学习 深度学习 神经网络
神经网络概念: 神经网络是一个由生物神经元组成的网络或电路,或者从现代意义上讲,是一个由人工神经元或节点组成的人工神经网络。因此,一个神经网络要么是由生物神经元组成的生物神经网络,要么是用于解决人工智能&…...
VCG 获取某个顶点的邻接顶点
文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 与之前的思路相同,这里我们利用VCG为我们提供的拓扑结构,获取某个顶点的邻接顶点,这在我们处理网格数据时往往很有用。 二、实现代码 //VCG #include <vcg/complex/algorithms/create/platonic.h> #inclu…...
四川云汇优想教育咨询有限公司电商服务靠谱吗
随着抖音电商的兴起,越来越多的商家开始关注这一领域。四川云汇优想教育咨询有限公司作为一家专注于电商服务的企业,也受到了广泛的关注。那么,四川云汇优想教育咨询有限公司的抖音电商服务靠谱吗?下面我们将从多个方面进行深入剖…...
Spring MVC框架支持RESTful,设计URL时可以使用{自定义名称}的占位符@Get(“/{id:[0-9]+}/delete“)
背景:在开发实践中,如果没有明确的规定URL,可以参考: 传统接口 获取数据列表,固定接口路径:/数据类型的复数 例如:/albums/select RESTful接口 - 根据ID获取某条数据:/数据类型的复数/{id} - 例…...
【GoLang】哪些大公司正在使用Go语言
你见过哪些令你膛目结舌的代码技巧? 文章目录 你见过哪些令你膛目结舌的代码技巧?前言:哪些大公司正在使用Go语言谷歌(Google):脸书(Facebook):亚马逊(Amazon…...
美团外卖商超商品销量数据
美团外卖商超商品月销量 字段名 店铺id 店铺名称 商品id 商品名称 商品分类 规格名 原价 现价 月销 规格属性 描述 商品图片 含商家月销量...
【C++高阶(八)】单例模式特殊类的设计
💓博主CSDN主页:杭电码农-NEO💓 ⏩专栏分类:C从入门到精通⏪ 🚚代码仓库:NEO的学习日记🚚 🌹关注我🫵带你学习C 🔝🔝 单例模式 1. 前言2. 设计一个不能被拷贝/继承的…...
Linux之进程(五)(进程控制)
目录 一、进程创建 1、fork函数创建进程 2、fork函数的返回值 3、fork常规用法 4、fork调用失败的原因 二、进程终止 1、进程终止的方式 2、进程退出码 3、进程的退出方法 三、进程等待 1、进程等待的必要性 2、wait函数 3、waitpid函数 四、进程程序替换 1、概念…...
63. 不同路径 II 23.12.21(二)
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。 现在考虑网格中有障碍物。那么从左上角到右下角…...
【线性代数】两个向量组等价,其中一个向量组线性无关,另一个向量组也是线性无关吗?
一、问题 两个向量组等价,其中一个向量组线性无关,另一个向量组也是线性无关吗? 二、答案 不一定,当两个向量组中的向量个数也相同时,结论才成立.若向量个数不相同,结论不成立. 例如: 向量组一:(1,0),(0,1) 向量组二:(1,0),(0,1),(1,1) 两…...
c语言:指针作为参数传递
探究实参与形参它们相互独立 由于主调函数的变量a,b与被调函数的形参x,y它们相互独立。函数 swap 可以修改变量x,y,但是却无法影响到主调函数中的a,b。 现在利用取地址运算符,分别打印它们的首地址&#x…...
YOLOv5性能评估指标->mAP、Precision、Recall、FPS、Confienc (讲解论文关注的主要指标)
简介 这篇博客,主要给大家讲解我们在训练yolov5时生成的结果文件中各个图片及其中指标的含义,帮助大家更深入的理解,以及我们在评估模型时和发表论文时主要关注的参数有那些。本文通过举例训练过程中的某一时间的结果来帮助大家理解…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
