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;
}

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

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

相关文章

undefined 和 null 有什么区别?

1、先看二者的相似处 &#xff08;1&#xff09;都属于JavaScript的7种基本类型 let primitiveTypes [string,number,null,undefined,boolean,symbol, bigint]; &#xff08;2&#xff09;都属于虚值 通过 Boolean(value) 或 !!value 转换为布尔值&#xff0c;且值都为fal…

codeforces D. Array Collapse

DP一生之敌 learn from AC-Panda and codeforces’s Tutorial 思路 d p [ i ] dp[i] dp[i] 表示以 a [ i ] a[i] a[i] 结尾的方案数&#xff0c; s u m [ i ] sum[i] sum[i] 表示 ∑ j 1 i d p j \sum\limits_{j1}^idp_j j1∑i​dpj​ 。对于 d p [ i ] dp[i] dp[i] 当 …

MySQL- SELECT ... FOR UPDATE语句

基本介绍 SELECT ... FOR UPDATE 是 SQL 语言中的一种语句&#xff0c;用于在数据库事务处理中控制并发访问。这种语句通常用在需要对数据库中的记录进行更新操作的场景中。下面是对 SELECT ... FOR UPDATE 的详细介绍&#xff1a; 用途&#xff1a;SELECT ... FOR UPDATE 用于…

智慧食堂餐卡充值文件生成器使用说明

智慧食堂餐卡充值文件生成器 下载地址&#xff1a; https://download.csdn.net/download/boysoft2002/88646277 或者百度网盘下载&#xff1a; https://pan.baidu.com/s/16cxOa5aq0CU0T0xOr2A7-A 操作使用说明 一、文件结构 下载.rar文件后&#xff0c;释放到非系统盘符的…

解决mp4视频无法拖动进度条的问题

现象: 海康威视的监控摄像头保存的视频&#xff0c;,mp4格式&#xff0c; 大小1G。用PotPlayer播放器进行播放&#xff0c; 不拖动进度条的话可以正常播放&#xff0c; 但拖动进度条后&#xff0c; 视频无法正常播放&#xff0c; 在 PotPlayer 中的表现就是只有进度条在走&…

TensorFlow(2):Windows安装TensorFlow

1 安装python环境 这一步请自行安装&#xff0c;这边不做介绍。 2 安装anaconda 下载路径&#xff1a;Index of /&#xff0c;用户自行选择自己的需要的版本。 3 环境配置 3.1 anaconda环境配置 找到设置&#xff0c;点击系统->系统信息->高级系统设置->环境变量…

ThinkPad E550c

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;…

基于YOLOv5的吸烟检测系统设计与实现

一、项目背景 吸烟检测作为保障公共健康和环境安全的重要任务之一&#xff0c;一直备受关注。传统的吸烟检测方法往往依赖人工判断&#xff0c;存在准确性低和实时性差的问题。为了解决这些问题&#xff0c;本项目基于深度学习技术进行了吸烟检测系统的设计与实现&#xff0c;…

buuctf-Misc 题目解答分解91-93

91.[SUCTF2018]followme 下载完就是一个流量包 &#xff0c;用wireshark 打开 直接导出 http对象 这里面 有很多的这样的文件 里面都是参数 直接搜索 关键字 suctf grep -r "SUCTF" 得到flag SUCTF{password_is_not_weak} 92.[MRCTF2020]CyberPunk 用notepad 打开…

【Ehcache技术专题】「入门到精通」带你一起从零基础进行分析和开发Ehcache框架的实战指南(5-检索开发)

系列文章目录 本系列课程主要针对于Ehcache缓存框架功能的开发实践全流程技术指南&#xff01; 第一节&#xff1a;Ehcache缓存框架的基本概念和简介第二节&#xff1a;Ehcache缓存框架的配置分析和说明第三节&#xff1a;Ehcache缓存框架的缓存方式的探索第四节&#xff1a;E…

隐藏通信隧道技术——防御SSH隧道攻击的思路

隐藏通信隧道技术——防御SSH隧道攻击的思路 ​ 在内网中建立一个稳定、可靠的数据通道&#xff0c;对渗透测试工作来说具有重要的意义。应用层的隧道通信技术主要利用应用软件提供的端口来发送数据。常用的隧道协议有SSH、HTTP/HTTPS和DNS。 SSH协议 在一般情况下&#xff…

PostgresSQL数据库中分区和分表的区别以及PostgresSQL创建表分区分表示例

1.分区分表理解 数据库分区和分表都是数据库中常用的数据分散存储技术&#xff0c;但它们的实现方式和应用场景有所不同。 分表&#xff1a;将一个大的表拆分成多个小的表&#xff0c;每个子表存储一部分数据。分表可以减轻单个表的数据量&#xff0c;提高查询效率&#xff0c…

计算机组成原理(复习题)

更多复习详情请见屌丝笔记 一、选择题 计算机系统概述 1、至今为止&#xff0c;计算机中的所有信息仍以二进制方式表示的理由是&#xff08; C &#xff09;。 A.运算速度快 B.信息处理方便 C.物理器件性能所致 D.节约元件 2、运算器的核心功能部件是&#xff08; D &am…

HarmonyOS应用开发者高级认证满分指南

声明&#xff1a;由于HarmonyOS应用开发者高级认证的题库一直在变&#xff0c;所以文章中的题目直做参考。 1. 判断题 云函数打包完成后&#xff0c;需要到APPGallery Connect创建对应函数的触发器才可以在端侧中调用。 【错】每一个自定义组件都有自己的生命周期。 【对】基…

【离散数学】——期末刷题题库(树其二)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

Flink SQL填坑记2:Flink和MySQL的Bigdata类型不同导致ClassCastException报错

最近在开发Flink SQL的时候,需要关联Kafka事实表和MySQL维表,得到的数据写入Phoenix表中,但是其中有个字段,Kafka表、MySQL表和Phoenix表都是BigData类型,但是在实现的时候却报“java.math.BigInteger cannot be cast to java.lang.Long”异常,从报错信息来看,是由于Big…

[CVPR-23] PointAvatar: Deformable Point-based Head Avatars from Videos

[paper | code | proj] 本文的形变方法被成为&#xff1a;Forward DeformationPointAvatar基于点云表征动态场景。目标是根据给定的一段单目相机视频&#xff0c;重建目标的数字人&#xff0c;并且数字人可驱动&#xff1b;通过标定空间&#xff08;canonical space&#xff09…

http -- 跨域问题详解(浏览器)

参考链接 参考链接 1. 跨域报错示例 Access to XMLHttpRequest at http://127.0.0.1:3000/ from origin http://localhost:3000 has been blocked by CORS policy: Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header…

【QT】解决QTableView修改合并单元格内容无法修改到合并范围内的单元格

问题:修改合并单元格的内容 修改合并单元格的内容时,希望直接修改到合并范围内的单元格,Qt没有实现这个功能,需要自己写出 Delegate来实现 方案:Delegate class EditDelegate : public QStyledItemDelegate {public:EditDelegate(QTableView *view): tableView(view){}pu…

JS基础之模块化

JS基础之模块化 JS模块化模块化前端发展 什么是模块&#xff1f;怎么定义模块化IIFE匿名函数自调用IIFE模式增强模块化的好处 JS模块化 模块化 JS DOM操作 代码规范管理的标准 不同模块间的管理模块内部自组织 标准bundler (模块构建工具) ESNext TS -> ES5 前端发展 生态 …