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

news2024/11/25 21:34:57

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() {
    
    //实例化一个对象为p1
    Person 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;
	} 



    //定义一个成员变量,属性为public
    int age;
};


void test01()
{   
    //实例化一个对象为p1,会调用有参构造函数
    Person p1(10);
    //打印p1.age的结果
    std::cout << "p1.age:" << p1.age << std::endl;

    //实例化一个对象为p2
    Person 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的值,调用构造函数后值都为0
    std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;

    //使用对象调用成员函数
    p1.ShowPerson();
    //查看此时变量p_a和p_b的值,p_a会变为10,p_b为0
    std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;

    //使用对象调用常量成员函数
    p1.ShowPerson2();
    //查看此时变量p_a和p_b的值,p_a会为10,p_b为22
    std::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.coloradmin.cn/o/1325466.html

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

相关文章

【spark】spark内核调度(重点理解)

目录 spark内核调度DAGDAG的宽窄依赖和阶段划分内存迭代计算面试题Spark是怎样做内存计算的&#xff1f;DAG的作用是什么&#xff1f;Stage阶段划分的作用&#xff1f;Spark为什么比MapReduce快 spark并行度如何设置并行度&#xff1a;spark.default.parallelism集群中如何规划…

P1 H264码流结构分析 (上)

目录 前言 01 什么是码流结构 02 H264帧类型的区别 03 片slice 前言 从本章开始我们将要学习嵌入式音视频的学习了 &#xff0c;使用的瑞芯微的开发板 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525…

官方指定Jmeter配置JVM堆内存方式

1.概述 在使用Jmeter做性能测试过程中&#xff0c;可能会应为默认设置的堆内存值较小出现堆内存溢出问题&#xff0c;此时解决的方式有两种&#xff0c;分布式测试和调大堆内存。下面介绍官方推荐调整堆内存方法。 2.调整Jmeter堆内存 2.1.介绍官方推荐堆内存调整方法(jmete…

IDEA Community html文件里的script标签没有syntax highlighting的解决方案

在网上找到的解决方法有的是针对Ultimate版本才可以下载的plugin&#xff0c;对我所用的Community版本无法生效&#xff0c;找了一圈最后在stackoverflow上找到一个有效的方案&#xff0c;给需要的小伙伴分享一下&#xff1a;IntelliJ Community Edition: Javascript syntax hi…

Jenkins 执行远程脚本的插件—SSH2 Easy

SSH2 Easy 是什么&#xff1f; SSH2 Easy 是一个 Jenkins 插件&#xff0c;它用于在 Jenkins 构建过程中通过 SSH2 协议与远程服务器进行交互。通过该插件&#xff0c;用户可以在 Jenkins 的构建过程中执行远程命令、上传或下载文件、管理远程服务器等操作。 以下是 SSH2 Eas…

7-4 JAVA-水仙花数(Java for PTA)

水仙花数是指一个N位正整数&#xff08;7≥N≥3&#xff09;&#xff0c;它的每个位上的数字的N次幂之和等于它本身。例如&#xff1a;153135333。 要求编写程序&#xff0c;计算所有N位水仙花数。 输入格式: 输入一个正整数N&#xff08;3≤N≤7&#xff09;。 输出格式: …

java并发编程四 Monitor 概念,api介绍与线程状态转换

Monitor 概念 Java 对象头 以 32 位虚拟机为例子&#xff1a; 普通对象 数组对象 其中 Mark Word 结构为 64 位虚拟机 Mark Word 小故事 故事角色 老王 - JVM小南 - 线程小女 - 线程房间 - 对象房间门上 - 防盗锁 - Monitor房间门上 - 小南书包 - 轻量级锁房间门上 -…

Elasticsearch常见面试题

文章目录 1.简单介绍下ES&#xff1f;2.简单介绍当前可以下载的ES稳定版本&#xff1f;3.安装ES前需要安装哪种软件&#xff1f;4.请介绍启动ES服务的步骤&#xff1f;5.ES中的倒排索引是什么&#xff1f;6. ES是如何实现master选举的&#xff1f;7. 如何解决ES集群的脑裂问题8…

本地文件内容搜索神器AnyTXT Searcher如何搭建与远程访问

文章目录 前言1. AnyTXT Searcher1.1 下载安装AnyTXT Searcher 2. 下载安装注册cpolar3. AnyTXT Searcher设置和操作3.1 AnyTXT结合cpolar—公网访问搜索神器3.2 公网访问测试 4. 固定连接公网地址 前言 你是否遇到过这种情况&#xff0c;异地办公或者不在公司&#xff0c;想找…

ubuntu qt 源码编译

官方源码下载地址 : 源码地址 选择要下载的版本 dmg结尾的是MacOS系统里使用的Qt库&#xff0c;qt-everywhere-opensource-src-4.7.0是Qt源码包&#xff0c;有zip和tar.gz两个压缩格式的&#xff0c;两个内容是一样的&#xff0c;只是zip一般在Windows下比较流行&#xff0c;…

【100个Cocos实例】快要圣诞节了,给大家支个招!

引言 Mask遮罩组件的一些简单实例 在游戏开发中常常需要在UI界面上展示玩家的头像或者Logo&#xff0c;通常都会是正方形。 偶尔也会有一些奇形怪状的需求&#xff0c;例如五边形、六边形、心形等等。 本文将介绍一下在Cocos游戏开发中Mask遮罩组件的一些简单实例&#xff…

九州未来向开放原子开源基金会捐赠OpenV2X,共建繁荣开源生态

12月16日&#xff0c;以“一切为了开发者”为主题的开放原子开发者大会在无锡成功举办。会上&#xff0c;九州未来将OpenV2X车路协同开源项目正式捐赠给开放原子开源基金会&#xff0c;并签署项目捐赠协议&#xff0c;通过开源共创的方式&#xff0c;携手开源伙伴共同打造车路协…

[微服务 ]微服务集成中的3个常见缺陷,以及如何避免它们

微服务风靡一时。他们有一个有趣的价值主张&#xff0c;即在与多个软件开发团队共同开发的同时&#xff0c;将软件快速推向市场。因此&#xff0c;微服务是在扩展您的开发力量的同时保持高敏捷性和快速的开发速度。 简而言之&#xff0c;您将系统分解为微服务。分解并不是什么新…

RLAIF方法与传说中的函数‘Q‘,揭露OpenAI那不为人知的Qstar计划

早晨刚起来,看群里新哥转了这个帖子: 帖子不长,但是基本是爆炸类的新闻了!这个应该也就是Sam之前被董事会诟病的所谓隐瞒了的真相! 在讲解这个帖子之前,先要普及2个概念: 1- RLAIF: 不是TGIF,虽然今天确实是周五 RLAIF是Google今年9月新出来的论文,论文…

智能优化算法应用:基于堆优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于堆优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于堆优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.堆优化算法4.实验参数设定5.算法结果6.参考文…

tcpdump抓包技巧

1. 常见的抓包工具 1.1 tcpdump 是Linux下常用的抓包工具&#xff0c;它是一个命令行工具&#xff0c;可以抓取和Wireshark类似的数据&#xff0c;而且保存的数据包&#xff0c;可以放到Wireshark中分析。如果你的Linux服务器需要抓包分析问题&#xff0c;它是一个非常好的选择…

算法基础之约数之和

约数之和 核心思想&#xff1a; #include<iostream>#include<algorithm>#include<vector>#include<unordered_map>using namespace std;typedef long long LL;const int N 110 , mod 1e97;int main(){int n;cin>>n;unordered_map<int,int&…

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

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

Python学习笔记(六):函数的多返回值、函数的多种参数使用形式、匿名函数、文件的读取操作、文件的写入 、文件的追加

目录 一、函数的多返回值 二、函数的多种参数使用形式 2.1位置参数 2.2关键字参数 2.3缺省参数 2.4不定长参数 三、匿名函数 3.1 函数作为参数传递 3.2 函数的定义 3.3 匿名函数定义语法&#xff1a; 四、文件的读取操作 4.1 open&#xff08;&#xff09;打开函数…

【WPF.NET开发】样式和模板

本文内容 示例样式ControlTemplateDataTemplate触发器视觉状态共享资源和主题 Windows Presentation Foundation (WPF) 样式设置和模板化是指一套功能&#xff0c;这套功能使开发者和设计者能够为其产品创建极具视觉表现力的效果和一致的外观。 自定义应用的外观时&#xff0…