[C++核心编程-06]----C++类和对象之对象模型和this指针

🎩 欢迎来到技术探索的奇幻世界👨‍💻

📜 个人主页:@一伦明悦-CSDN博客

✍🏻 作者简介: C++软件开发、Python机器学习爱好者

🗣️ 互动与支持:💬评论      👍🏻点赞      📂收藏     👀关注+

如果文章有所帮助,欢迎留下您宝贵的评论,点赞加收藏支持我,点击关注,一起进步!


目录

引言                   

正文

01-对象模型和this指针简介                   

02-成员变量和成员函数分开存储                   

03-this指针                   

04-空指针访问成员函数                  

总结                  


引言                   

        在C++中,类是一种用于描述一类对象的数据结构,而对象则是根据类定义创建的实例。类定义了对象的属性和方法,而对象是类的具体实例化。在C++中,类和对象一起构成了面向对象编程的基础。

        在C++中,对象模型是用来描述类和对象之间关系的一种模型。在C++中,每个对象都有自己的一组成员变量和方法,这些成员变量和方法定义在类中。当创建一个对象时,该对象会占用一些内存空间来存储其成员变量,并且会有一个指向类的指针,这个指针指向该对象所属的类。

        this指针是一个隐含的指针,它指向当前对象的地址。在类的成员函数中,可以使用this指针来访问当前对象的成员变量和方法。this指针的类型是指向当前类的指针。

正文

01-对象模型和this指针简介                   

        在C++中,对象模型和this指针是面向对象编程的两个重要概念,它们有助于理解类和对象之间的关系以及在类的成员函数中操作对象的方式。

        对象模型:

        对象模型是用来描述类和对象之间关系的一种模型,它包括了对象的内存布局和对象访问的机制。在C++中,每个对象都有自己的一组成员变量和方法,这些成员变量和方法定义在类中。当创建一个对象时,该对象会占用一些内存空间来存储其成员变量,并且会有一个指向类的指针,这个指针指向该对象所属的类。

        this指针:

        this指针是一个隐含的指针,它指向当前对象的地址。在类的成员函数中,可以使用this指针来访问当前对象的成员变量和方法。this指针的类型是指向当前类的指针。通过this指针,可以在成员函数中区分当前对象和其他对象。

        详细总结:

      (1)对象模型

        a、对象模型描述了类和对象之间的关系,包括对象的内存布局和访问机制。

        b、每个对象都有自己的一组成员变量和方法,这些成员定义在类中。

        c、创建对象时,会为其分配内存空间,并有一个指向类的指针。

       (2)this指针

         a、this指针是一个隐含的指针,在类的成员函数中自动被创建。

         b、this指针指向当前对象的地址,允许在成员函数中访问当前对象的成员变量和方法。

         c、可以用来区分当前对象和其他对象,在处理对象自身的操作时非常有  

        下面是一个简单的示例,展示了对象模型和this指针的使用:

        在上面的示例中,定义了一个名为MyClass的类,该类有一个成员变量value和两个成员函数setValue和printValue。在setValue函数中,使用this指针来设置当前对象的value值,在printValue函数中,使用this指针来打印当前对象的value值。

        在main函数中创建了两个MyClass的对象obj1和obj2,分别调用了setValue和printValue函数来设置和打印对象的value值。

        通过这个示例,可以看到类和对象之间的关系以及如何使用this指针来操作当前对象的成员变量和方法。

#include <iostream>class MyClass {
public:int value;void setValue(int value) {this->value = value; // 使用this指针设置当前对象的value值}void printValue() {std::cout << "Value: " << this->value << std::endl; // 使用this指针打印当前对象的value值}
};int main() {MyClass obj1;MyClass obj2;obj1.setValue(10);obj2.setValue(20);obj1.printValue(); // 打印obj1的value值obj2.printValue(); // 打印obj2的value值return 0;
}

02-成员变量和成员函数分开存储                   

        在C++中,成员变量和成员函数是分开存储的,这是为了提高内存的利用率和程序的执行效率。成员变量存储在对象的内存空间中,而成员函数则存储在类的代码段中,所有对象共享同一份成员函数的代码。

        成员变量存储:

        成员变量是属于对象的数据,每个对象都有自己的一份成员变量。当创建一个对象时,系统会为其分配内存空间来存储成员变量,这些成员变量的大小取决于其类型和数量。每个对象的成员变量存储在其所占用的内存空间中,不同对象的成员变量是相互独立的。

        成员函数存储:

        成员函数是属于类的行为,它们被定义在类的内部,但并不存储在对象的内存空间中。相反,成员函数的代码只存储了一份,它们被存储在类的代码段中。所有属于同一个类的对象共享同一份成员函数的代码,这样可以节省内存空间。

        详细解释:

        (1)成员变量存储

        a、成员变量是对象的数据,每个对象都有自己的一份成员变量。

        b、当创建对象时,系统会为其分配内存空间来存储成员变量。

        c、不同对象的成员变量存储在各自的内存空间中,彼此独立。

        (1)成员函数存储

        a、成员函数是类的行为,它们被定义在类的内部。

        b、成员函数的代码存储在类的代码段中,而不是存储在对象的内存空间中。

        c、所有属于同一个类的对象共享同一份成员函数的代码,这样可以节省内存空间。

        下面是一个简单的示例,展示了成员变量和成员函数的存储方式:在这个示例中,可以看到成员变量value存储在每个对象的内存空间中,而成员函数setValue和getValue的代码只存储了一份,它们被所有对象共享。

#include <iostream>class MyClass {
public:int value; // 成员变量void setValue(int val) { // 成员函数value = val; // 访问成员变量}int getValue() { // 成员函数return value; // 返回成员变量的值}
};int main() {MyClass obj1, obj2; // 创建两个对象obj1.setValue(10); // 设置对象1的值obj2.setValue(20); // 设置对象2的值std::cout << "Value of obj1: " << obj1.getValue() << std::endl; // 获取并打印对象1的值std::cout << "Value of obj2: " << obj2.getValue() << std::endl; // 获取并打印对象2的值return 0;
}

        下面给出具体的代码进行分析成员变量和成员函数的使用过程:

        这个示例展示了C++中成员变量和成员函数分开存储的情况。在这个示例中,定义了一个名为Person的类,其中包括了非静态成员变量m_A,静态成员变量m_B,非静态成员函数func和静态成员函数func1。

        在函数test01中创建了一个Person对象p,并使用sizeof操作符来输出对象p所占用的字节数。即使对象p是空的,C++编译器也会分配一个字节的空间来区分空对象的内存位置,确保每个对象都有一个独一无二的内存地址。

        在函数test02中再次创建了一个Person对象p,并输出其占用的字节数,结果应该和test01中的一样。

        通过这个示例可以看到,在C++中,即使是空对象也会占用一定的内存空间,同时也展示了成员变量和成员函数分开存储的情况。

#include <iostream>
using namespace std;// 成员变量和成员函数分开存储
class Person
{int m_A;   // 非静态成员变量   属于类对象上static int m_B;  // 静态 不属于类对象上void func() {}  // 非静态成员函数,也不属于类对象上static void func1() {}  // 静态成员函数 不属于类对象上
};void test01()
{Person p;// 空对象占用字节// C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象所占内存的位置// 每个空对象也应该有一个独一无二的内存地址cout << "size of p = " << sizeof(p) << endl;
}void test02()
{Person p;cout << "size of p = " << sizeof(p) << endl;
}int main()
{test02();system("pause");return 0;
}

        示例运行结果如下图所示:

03-this指针                   

        在C++中,this指针是一个隐含的指针,它指向当前对象的地址。this指针在类的成员函数中自动被创建,并且可以用来访问当前对象的成员变量和成员函数。通过this指针,可以在成员函数中区分当前对象和其他对象,从而实现对当前对象的操作。

        详细解释:

        (1)this指针的作用

        a、this指针指向当前对象的地址,允许在成员函数中访问当前对象的成员变量和成员函数。

        b、当多个对象同时存在时,this指针可以帮助区分当前对象和其他对象,确保操作的是正确的对象。

        (2)this指针的类型

        a、this指针的类型是指向当前类的指针,因此在成员函数中可以直接访问当前类的成员。

        b、在成员函数中,可以通过this->成员变量或this->成员函数的方式来访问当前对象的成员变量和成员函数。

       (3)this指针的隐含性

        a、在类的成员函数中,this指针是隐含的,不需要显式地声明或传递。

        b、当调用成员函数时,编译器会自动将当前对象的地址传递给this指针。

         接下来给出具体代码分析展示了this指针的使用:详细解释代码如下:

        这段代码演示了如何使用this指针在C++中访问对象的成员变量。在类MyClass中,定义了一个私有成员变量value和两个公有成员函数setValuegetValue。在setValue函数中,使用了this指针来设置当前对象的value值,而在getValue函数中,使用this指针来获取当前对象的value值。

        在main函数中,创建了两个MyClass对象obj1obj2,分别设置了它们的value值为10和20,并通过调用getValue函数获取并打印了它们的value值。

        这段代码展示了this指针的隐含性和作用,通过this指针可以在成员函数中准确地访问当前对象的成员变量,确保操作的是正确的对象。

#include <iostream>class MyClass {
private:int value;public:void setValue(int value) {this->value = value; // 使用this指针设置当前对象的value值}int getValue() {return this->value; // 使用this指针获取当前对象的value值}
};int main() {MyClass obj1, obj2;obj1.setValue(10); // 设置obj1的value值obj2.setValue(20); // 设置obj2的value值std::cout << "Value of obj1: " << obj1.getValue() << std::endl; // 获取并打印obj1的value值std::cout << "Value of obj2: " << obj2.getValue() << std::endl; // 获取并打印obj2的value值return 0;
}

        下面给出具体的代码进行分析this指针的使用过程:这个示例展示了在C++中使用this指针解决名称冲突和返回对象本身的情况。在这个示例中,定义了一个名为Person的类,其中包括了一个构造函数和成员函数PersonAddAge,以及一个整型成员变量age。

        解决名称冲突:在函数test01中,创建了一个Person对象p1并初始化其年龄为18,在构造函数中使用了this指针来设置对象的年龄。通过this指针,可以准确地访问当前对象的成员变量,避免与函数参数或局部变量发生冲突。

        返回对象本身:在函数test02中,创建了两个Person对象p1和p2,并多次调用PersonAddAge函数来累加p1对象的年龄到p2对象。在PersonAddAge函数中,使用了this指针来访问当前对象的成员变量,同时返回值类型为Person&,表示返回的是当前对象的引用,实现了对同一个对象连续调用多次函数的链式操作。

        在test02函数中,通过链式调用的方式,三次调用PersonAddAge函数将p1对象的年龄累加到p2对象中,最终输出了p2对象的年龄。

        值得注意的是,在链式调用时需要确保PersonAddAge函数返回的是当前对象的引用(*this),这样才能保证连续调用的有效性。

        通过这个示例,展示了this指针在成员函数中的作用,以及如何使用this指针解决名称冲突和实现返回对象本身的功能。

#include <iostream>
using namespace std;class Person
{
public:Person(int age){// this指针指向的是被调用的成员函数所属的对象this->age = age;   }Person& PersonAddAge(Person &p){this->age += p.age;return *this;   // this指向的是p2的指针,而*this指向的就是p2这个对象本体}int age;   // 这里一般会定义的时候,尽量与构造函数传入的参数分辨清楚,或者在构造函数里加入this
};// 1、解决名称冲突
void test01()
{Person p1(18);cout << "p1的年龄: " << p1.age << endl;}// 2、返回对象本身用 return *this 且返回值类型,为该对象的类,加引用方式返回void test02()
{Person p1(10);Person p2(10);//	p2.PersonAddAge(p1);// 若想使用链式的方法多次相加,需要进行成员函数更改/* 具体方面如下1、当成员函数PersonAddAge()执行一次之后,返回值是void2、返回值是void,当然不能再对该成员函数进行调用,因此,返回值必须是p2才可以3、而这里说了返回对象本身用 return *this 且返回值类型,为该对象的类,加引用方式返回4、因此改成Person &PersonAddAge(Person &p){this->age += p.age;return *this;}*/p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);cout << "p2的年龄为:" <<p2.age<< endl;}int main()
{//test01();test02();system("pause");return 0;
}

        示例运行结果如下图所示:

04-空指针访问成员函数                  

        在C++中,空指针访问成员函数是指在一个空指针上调用成员函数的情况。空指针是指未指向任何有效对象的指针,即其存储的地址为0或nullptr。当尝试在空指针上调用成员函数时,由于没有有效对象来执行函数,可能会导致程序崩溃或未定义的行为。

        空指针的含义

        空指针是指未指向任何有效对象的指针,通常表示为nullptr(在C++11及以后版本)或0(在较早的C++版本中)。

        空指针不指向任何有效的内存地址,因此在其上调用成员函数将导致未定义的行为。

        空指针访问成员函数的影响

        当在空指针上调用成员函数时,由于没有有效的对象来执行函数体,程序可能会发生崩溃或产生未定义的行为。

        这是因为成员函数通常需要访问对象的成员变量或其他成员函数,而空指针并不指向任何对象,因此无法执行成员函数的操作。

        下面是一个简单的示例,演示了空指针访问成员函数的情况:

        在这个示例中,创建了一个名为MyClass的类,其中包含一个成员函数printMessage用于打印消息。在main函数中,创建了一个空指针ptr,并尝试在其上调用printMessage成员函数。

        然而,由于ptr是一个空指针,它并不指向任何有效的对象,因此在调用printMessage函数时将导致未定义的行为,可能会导致程序崩溃或产生其他意外结果。

#include <iostream>class MyClass {
public:void printMessage() {std::cout << "Hello, world!" << std::endl;}
};int main() {MyClass* ptr = nullptr; // 创建一个空指针ptr->printMessage(); // 尝试在空指针上调用成员函数return 0;
}

        解决方法:

        为了避免空指针访问成员函数导致的问题,可以在调用成员函数之前进行空指针的有效性检查,确保指针不为空才进行调用。例如:通过这样的有效性检查,可以避免空指针访问成员函数带来的潜在问题,增加程序的健壮性和稳定性。

if (ptr != nullptr) {ptr->printMessage();
} else {// 处理空指针的情况,如输出错误信息或进行其他操作std::cerr << "Error: Pointer is null." << std::endl;
}

下面给出具体代吗分析应用:

#include <iostream>
using namespace std;// 空指针调用成员函数class Person
{
public:void showClassName(){cout << "this is Person class" << endl;}void showPersonAge(){// 这里传入的指针为空,将会报错if (this == NULL)   // 这个判断可以防止传入空指针出错{return;}cout << "年龄age = " << m_Age << endl;}int m_Age;
};void test01()
{Person *p = NULL;p->showClassName();// 这里出错,主要原因如下/* 1、cout << "年龄age = " << m_Age << endl;这句代码里m_Age这里默认是this->m_Age2、但是这里定义的对象只是一个空指针,对于一个空指针来说,访问里面的成员是不可能的*/p->showPersonAge();}int main()
{test01();//test02();system("pause");return 0;
}

         示例运行结果如下图所示:

总结                  

        在C++中,对象模型和this指针是面向对象编程的两个重要概念,它们有助于理解类和对象之间的关系以及在类的成员函数中操作对象的方式。

        在C++中,对象模型是用来描述类和对象之间关系的一种模型。在C++中,每个对象都有自己的一组成员变量和方法,这些成员变量和方法定义在类中。当创建一个对象时,该对象会占用一些内存空间来存储其成员变量,并且会有一个指向类的指针,这个指针指向该对象所属的类。

        this指针是一个隐含的指针,它指向当前对象的地址。在类的成员函数中,可以使用this指针来访问当前对象的成员变量和方法。this指针的类型是指向当前类的指针。

 

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

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

相关文章

Day 43 1049. 最后一块石头的重量 II 494. 目标和 474.一和零

最后一块石头重量Ⅱ 有一堆石头&#xff0c;每块石头的重量都是正整数。 每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&#xff0c;且 x < y。那么粉碎的可能结果如下&#xff1a; 如果 x y&#xff0c;那么两…

drawio 网页版二次开发(2):开始修改代码

目录 一 说明 二 打开开发环境 1. 代码调整 2. 修改访问链接 3. 注意 三 部分功能的代码汇总 1. 保存功能 2. 菜单栏折叠按钮功能 3. 顶部菜单栏 4.在顶部菜单栏中的【文件】菜单中新增选项 &#xff08;1&#xff09; 方法一&#xff1a;单独增加 &#xff08;…

中北大学软件学院javaweb实验二JSP应用开发实验报告

实验时间 2024年4月 25 日17时至 22 时 学时数 4 1.实验名称 实验2&#xff1a;JSP应用开发(2学时) 2.实验目的 &#xff08;1&#xff09;学会编写和运行简单的JSP页面&#xff0c;理解其运行原理&#xff1b; &#xff08;2&#xff09;学会使用JSP的声明、表达式、脚…

Python数据科学 | ​Python 离群点检测算法 -- GMM

本文来源公众号“Python数据科学”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;​Python 离群点检测算法 -- GMM 星星在天空中聚集或分散&#xff0c;呈现出自然的分布。在统计学中&#xff0c;K-均值法是一种著名的聚类技术&a…

Aapache Tomcat AJP 文件包含漏洞(CVE-2020-1938)

1 漏洞描述 CVE-2020-1938 是 Apache Tomcat 中的一个严重安全漏洞&#xff0c;该漏洞涉及到 Tomcat 的 AJP&#xff08;Apache JServ Protocol&#xff09;连接器。由于 AJP 协议在处理请求时存在缺陷&#xff0c;攻击者可以利用此漏洞读取服务器上的任意文件&#xff0c;甚至…

keil5软件安装教程(MDKv5.39)

keil5软件安装分为三部分&#xff1a; 目录 1.安装mdk 2.激活mdk 3.安装STM32芯片包 1.安装mdk 安装包链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1PZoGhzI5Y19ROv7xe9QJKA?pwdgt3s 提取码&#xff1a;gt3s 1、下载keil5的压缩包并解压&#xff0c;鼠…

通俗的理解网关的概念的用途(三):你的数据包是如何到达下一层的

其实&#xff0c;这一章我写不好&#xff0c;因为这其中会涉及到一些计算和一些广播等概念&#xff0c;本人不善于此项。在此略述&#xff0c;可以参考。 每台设备的不同连接在获得有效的IP地址后&#xff0c;会根据IP地址的规则和掩码的规则&#xff0c;在操作系统和交换机&a…

【C++】继承 — 继承的引入、赋值切片详细讲解

前言 我们知道C语言是一门面向对象编程的语言&#xff0c;而面向对象编程有三大特性&#xff0c;它们分别是&#xff1a; 封装继承多态 目录 1. 继承的概念及定义1.1继承的概念1.2继承的定义格式1.3 继承的使用 2 基类和派生类对象赋值转换3 继承中的作用域3.1 派生类对象的存…

基于springboot+vue+Mysql的体质测试数据分析及可视化设计

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

Windows11提示升级,我要点确定吗?

Windows 11自2021年10月推出以来&#xff0c;一直保持着缓慢而稳定的增长&#xff0c;相对来说在游戏PC上的影响力较大&#xff0c; 而Windows 10也即将于2025年10月结束支持。 截至2024年&#xff0c;Windows 11的主要版本包括24H2、 23H2、22H2和21H2。 24H2&#xff1a;20…

5月白银现货最新行情走势

美联储5月的议息会议举行在即&#xff0c;但从联邦公开市场委员会&#xff08;FOMC&#xff09;近期透露的信息来看&#xff0c;降息似乎并没有迫切性。——美联储理事鲍曼认为通胀存在"上行风险"&#xff0c;明尼阿波利斯联邦储备银行行长卡什卡利提出了今年不降息的…

数学:人工智能领域的基石与灵魂

在科技日新月异的今天&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到了我们生活的方方面面&#xff0c;从智能家居、智能医疗到自动驾驶、智能客服&#xff0c;AI无处不在。然而&#xff0c;当我们赞叹于AI的神奇时&#xff0c;却往往忽视了其背后的推动力——数学…

5月游戏市场迎来新的体验,网易两款游戏重磅出炉

易采游戏网5月9日消息&#xff0c;随着科技的飞速发展&#xff0c;手机游戏已经成为人们休闲娱乐的重要方式。在这个领域&#xff0c;网易作为国内领先的游戏开发商&#xff0c;一直致力于为玩家带来高品质的游戏体验。近日&#xff0c;网易携手国际大厂Square Enix&#xff0c…

列表、字典推导式介绍和用法|lambda的介绍和用法

列表、字典推导式介绍和用法|lambda的介绍和用法 列表推导式示例应用与传统写法代码行数直观比较 字典推导式示例应用 lambda示例应用 列表推导式、字典推导式、lambda使用简洁语法进行代码的编写 列表推导式 用于快速创建新的列表&#xff0c;通过对现有列表进行迭代和筛选。…

技术速递|Python in Visual Studio Code 2024年5月发布

排版&#xff1a;Alan Wang 我们很高兴地宣布 Visual Studio Code 的 Python 和 Jupyter 扩展将于 2024 年 5 月发布&#xff01; 此版本包括以下公告&#xff1a; “Implement all inherited abstract classes”代码操作新的自动缩进设置Debugpy 从 Python 扩展中删除&#…

vivado新版本兼容老版本,vitis classic兼容sdk教程

new version: vivado版本2023.2 和vitisv classic 2023.2 old version: vivado 2018.3以及之前的版本 打开工程 自动升级到当前版本&#xff0c;选择OK 点击Yes,合并当前的目录架构 点击OK 点击Report IP status 勾选要升级的IP核&#xff0c;点击升级 在项目工程文件夹…

Java医院绩效考核系统源码maven+Visual Studio Code一体化人力资源saas平台系统源码

Java医院绩效考核系统源码mavenVisual Studio Code一体化人力资源saas平台系统源码 医院绩效解决方案包括医院绩效管理&#xff08;BSC&#xff09;、综合奖金核算&#xff08;RBRVS&#xff09;&#xff0c;涵盖从绩效方案的咨询与定制、数据采集、绩效考核及反馈、绩效奖金核…

Hadoop | 数据清洗

# 数据清洗概念 通常情况下&#xff0c;大数据平台获得原始数据文件中&#xff0c;存在大量无效数据和缺失数据&#xff0c;需要再第一时间&#xff0c;对数据进行清洗&#xff0c;获得符合后续处理需求的数据内容和格式 # 需求 对手机流量原始数据&#xff0c;将其中的手机号…

《Decoupled Contrastive Learning for Long-Tailed Recognition》阅读笔记

论文标题 《Decoupled Contrastive Learning for Long-Tailed Recognition》 针对长尾识别的解耦对比学习 作者 Shiyu Xuan 和 Shiliang Zhang 来自北京大学计算机学院多媒体信息处理国家重点实验室 初读 摘要 监督对比损失&#xff08;Supervised Contrastive Loss, SC…

使用GitLab自带的CI/CD功能在远程服务器部署项目(三)

前置内容&#xff1a; 通过Docker Compose部署GitLab和GitLab Runner&#xff08;一&#xff09; 使用GitLab自带的CI/CD功能在本地部署项目&#xff08;二&#xff09; 目录 一、在GitLab服务器上生成私钥与公钥 二、将公钥拷贝到应用服务器上 三、将私钥给到Docker Exec…