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; // 260
    h.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="无名" ) { // _ZN5Human7setinfoEiPKc
        this->m_age = age;
        strcpy( this->m_name, name ); 
    }
    void getinfo( /* Human* this */ ) { // _ZN5Human7getinfoEv
        cout << "姓名:" << 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; // 260
    h.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; // 编译器补this

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

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

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

相关文章

力扣79. 单词搜索(java DFS解法)

Problem: 79. 单词搜索 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 该问题可以归纳为一类遍历二维矩阵的题目&#xff0c;此类中的一部分题目可以利用DFS来解决&#xff0c;具体到本题目&#xff08;该题目可以的写法大体不变可参看前面几个题目&#xff1a;&…

校园圈子交友系统,APP小程序H5,三端源码交付,支持二开!实名认证,大V认证,地图找伴,二手平台!

校园圈子交友系统&#xff0c;是属于自主定义开发的系统&#xff0c;内容有很多&#xff0c;先截取一些给大家看看&#xff0c;让大家更多的了解本系统&#xff0c;然后再做评价&#xff01; 校园后端下载地址&#xff1a;校园圈子系统小程序&#xff0c;校园拼车&#xff0c;校…

Netty Review - StringEncoder字符串编码器和StringDecoder 解码器的使用与源码解读

文章目录 概念概述StringEncoderStringDecoder Code源码分析StringEncoderStringDecoder 小结 概念 概述 Netty是一个高性能的网络应用程序框架&#xff0c;它提供了丰富的功能&#xff0c;包括编解码器&#xff0c;这些编解码器用于在网络中发送和接收数据时进行数据的编码和…

mac电脑安装虚拟机教程

1、准备一台虚拟机&#xff0c;安装CentOS7 常用的虚拟化软件有两种&#xff1a; VirtualBoxVMware 这里我们使用VirtualBox来安装虚拟机&#xff0c;下载地址&#xff1a;Downloads – Oracle VM VirtualBox 001 点击安装 002 报错&#xff1a;he installer has detected an…

uni-app 用于开发H5项目展示饼图,使用ucharts 饼图示例

先下载ucharts H5示例源码&#xff1a; uCharts: 高性能跨平台图表库&#xff0c;支持H5、APP、小程序&#xff08;微信小程序、支付宝小程序、钉钉小程序、百度小程序、头条小程序、QQ小程序、快手小程序、360小程序&#xff09;、Vue、Taro等更多支持canvas的框架平台&#…

在Windows系统平台下部署运行服务端Idea工程的jar服务

前言 目前云原生docker等技术&#xff0c;加上部署流水线大大的简化了各种流程&#xff0c;我们后端开发的人员只需要提交代码后&#xff0c;构建、部署、测试、发布等环节都无需人员接入&#xff0c;完全的自动化交付了。那么你肯定不禁想问&#xff0c;如题的需求不是点击一…

pyCharm 创建一个FastApi web项目,实现接口调用

FastApi和Django区别 我这边演示项目使用的fastApi作为web框架&#xff0c;当然主流一般都是使用Django做web框架&#xff0c;但是Django是一个重量级web框架他有很多组件&#xff0c;如授权&#xff0c;分流等全套web功能。我这边呢只需要有个接口可以被别人调用&#xff0c;…

python 绘制网格图/马赛克图

python 绘制网格图/马赛克图 文章目录 python 绘制网格图/马赛克图前言 前言 python绘制网格并在相应的坐标填充颜色 参考博客 def mplot_intf(t, data):plt.rcParams["figure.figsize"] (t, len(data))plt.rcParams["xtick.major.size"] 0plt.rcParams…

ios微信小程序table头部与左侧固定双重滚动会抖动的坑,解决思路

正常情况是左右滑动时&#xff0c;左侧固定不动&#xff0c;上下滑动时表头不动&#xff1b;而且需求不是完整页面滚动。而是单独这个表滚动&#xff1b; 第一个坑是他有一个ios自带的橡胶上下回弹效果。导致滚动时整个表都跟着回弹&#xff1b; 这个是很好解决。微信开发官网…

Achronix提供由FPGA赋能的智能网卡(SmartNIC)解决方案来打破智能网络性能极限

作者&#xff1a;Achronix 随着人工智能/机器学习&#xff08;AI/ML&#xff09;和其他复杂的、以数据为中心的工作负载被广泛部署&#xff0c;市场对高性能计算的需求持续飙升&#xff0c;对高性能网络的需求也呈指数级增长。高性能计算曾经是超级计算机这样一个孤立的领域&a…

【控制器局域网】CAN报文学习笔记(四)之 字节排序、信号提取实例1

以下面的表格来表示字节顺序和位顺序&#xff0c;用红色表示高位MSB&#xff0c;蓝色表示低位LSB&#xff0c;绿色为LSB到MSB的过度 Bit oderMSB→→→→→→LSBByte oder\Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0MSBByte076543210↓Byte115141312111098↓Byte22322212019181716↓By…

谷歌手机安装证书到根目录

1、前提你已经root&#xff0c;安装好面具 2&#xff0c;下载movecert模块&#xff0c;自动帮你把证书从用户证书移动成系统证书 视频教程&#xff0c;手机为谷歌手机 https://www.bilibili.com/video/BV1pG4y1A7Cj?p11&vd_source9c0a32b00d6d59fecae05b4133f22f06 软件下…

【C语言指针专题(4)】指针与一维数组

一、数组名的理解 在之前我们我们使用指针访问数组的时候&#xff0c;使用到了这样一段代码&#xff1a; int arr[10] { 0 }; int* pa &arr[0]; 这里我们使用 &arr[0] 的方式拿到了数组第一个元素的地址&#xff0c;但是其实数组名本来就是地址&#xff0c;而且 是…

使用opencv实现图像中几何图形检测

1 几何图形检测介绍 1.1 轮廓(contours) 什么是轮廓&#xff0c;简单说轮廓就是一些列点相连组成形状、它们拥有同样的颜色、轮廓发现在图像的对象分析、对象检测等方面是非常有用的工具&#xff0c;在OpenCV 中使用轮廓发现相关函数时候要求输入图像是二值图像&#xff0c;这…

麒麟V10 ARM 离线生成RabbitMQ docker镜像并上传Harbor私有仓库

第一步在外网主机执行&#xff1a; docker pull arm64v8/rabbitmq:3.8.9-management 将下载的镜像打包给离线主机集群使用 在指定目录下执行打包命令&#xff1a; 执行&#xff1a; docker save -o rabbitmq_arm3.8.9.tar arm64v8/rabbitmq:3.8.9-management 如果懒得打包…

力扣:77. 组合(回溯, path[:]的作用)

题目&#xff1a; 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ] 示例 2&#xff1a; 输入&…

机器学习数据的清洗,转化,汇总及建模完整步骤(基于Titanic数据集)

目录 介绍&#xff1a; 一、数据 二、检查数据缺失 三、数据分析 四、数据清洗 五、数据类别转化 六、数据汇总和整理 七、建模 介绍&#xff1a; 线性回归是一种常用的机器学习方法&#xff0c;用于建立一个输入变量与输出变量之间线性关系的预测模型。线性回归的目标…

Inkscape SVG 编辑器 导入 Gazebo

概述 本教程描述了拉伸 SVG 文件的过程&#xff0c;这些文件是 2D 的 图像&#xff0c;用于在 Gazebo 中为您的模型创建 3D 网格。有时是 更容易在 Inkscape 或 Illustrator 等程序中设计模型的一部分。 在开始之前&#xff0c;请确保您熟悉模型编辑器。 本教程将向您展示如…

神经网络:池化层知识点

1.CNN中池化的作用 池化层的作用是对感受野内的特征进行选择&#xff0c;提取区域内最具代表性的特征&#xff0c;能够有效地减少输出特征数量&#xff0c;进而减少模型参数量。按操作类型通常分为最大池化(Max Pooling)、平均池化(Average Pooling)和求和池化(Sum Pooling)&a…

使用STM32微控制器读取和显示DHT11温湿度传感器数据

在本文中&#xff0c;我们将介绍如何使用STM32微控制器读取和显示DHT11温湿度传感器的数据。我们将使用C语言和STM32的库函数来实现这个功能。本文包含硬件连接和软件编程两个方面的内容。 硬件连接 首先&#xff0c;我们需要将DHT11温湿度传感器连接到STM32微控制器上。DHT11…