【C++入门】浅谈类、对象和 this 指针

文章目录

  • 一、前言
  • 二、类
    • 1. 基本概念
    • 2. 类的封装
    • 3. 使用习惯
      • 成员函数定义习惯
      • 成员变量命名习惯
  • 三、对象
    • 1. 基本概念
    • 2. 类对象的存储规则
  • 四、this 指针
    • 1. 基本概念
    • 2. 注意事项
    • 3. 经典习题
    • 4. 常见面试题

一、前言

在 C 语言中,我们用结构体来描述一个事物的多种属性。

struct person
{int age;char name[10];
};

而 C++ 则引入了类,相比结构体内只能定义变量,类还可以定义函数。
下面声明一个类,类名为person

//class关键字
class person
{void init(...){...}int age;char name[10];
};

上面代码只是类的声明,没有占用实际的空间。
用类创建对象,称作类的实例化。
实例化的对象才会占用实际的物理空间。

创建对象:类名 + 对象名
例子:

person a;

上述代码创建了一个person类的对象a,对象才占有实际空间。

而 C 语言中的struct关键字,在 C++ 中也升级成了类,不过 C++ 中的struct关键字依然兼容 C语言的结构体写法。

//C++ 中的类
struct person
{void init(...){...}int age;char name[10];
};
//创建一个person类的对象b
person b;//C 语言中的结构体
struct person
{int age;char name[10];
};
//创建一个结构体变量c
struct person c;
//也可以这样写,此时person被看作一个类
person c;

二、类

1. 基本概念

类中的内容称为成员。
类中的变量称为属性或成员变量,类中的函数称为方法或成员函数。

2. 类的封装

C++ 中的类是用于实现封装的,封装是面向对象的三大特性之一,简单来说,封装就是将对象的属性和方法有机结合,隐藏内部实现细节,仅对外提供接口用于交互。就像电脑主机内部封装了各种硬件的实现细节,仅提供开机按钮、鼠标和键盘等让用户和计算机交互。
如何隐藏内部实现细节呢,C++ 提供了三个访问限定符,publicprivateprotected
public修饰的成员可以在类外访问,privateprotected修饰的成员不能在类外访问。
class的默认访问权限为privatestructpublic

3. 使用习惯

成员函数定义习惯

第一种是成员函数的声明和定义都在类中。

class person
{
public:void print(){...}
private:int age;char name[10];
};

需要注意的是,这种方式的成员函数定义在类中,编译器可能会将其当作内联函数处理。

另一种则是成员函数的声明在类中(类在头文件声明),定义体在类外(cpp文件)。一般建议使用这种方式。

//person.h
class person
{
public:void print();private:int age;char name[10];
};//person.cpp
void person::print()//注意要加 person::
{...
}

一个类就是一个新的作用域(事实上,C++ 中一对大括号就是一个域),类的所有成员都在类的域中,因此在类外定义类的成员函数时,函数名前要加类名::

成员变量命名习惯

一般会给变量名加个前缀或后缀,用于区分成员变量和成员函数形参。

例子:

class person
{
public:void init(int age, char name[]){...}
private:int _age;       //或 mAgechar _name[10]; //或 mName
};

三、对象

1. 基本概念

简单来说,类是对一类事物的抽象描述,只是一个声明,不占物理空间。而类的对象就是类的一个实例化,是真实存在在内存空间的。

2. 类对象的存储规则

一个类对象在内存中只会存储它的成员变量,成员函数则是放在公共代码区,供类的所有对象使用。

那么如何计算sizeof类对象的大小呢?
事实上,类对象的大小等价于类的大小,因为sizeof是根据类型确定大小的。
而类对象中只存储它的成员变量,因此只需计算类的所有成员变量所占空间的大小即可。
与 C 语言中计算结构体的大小相同,计算类的大小也要考虑内存对齐的规则,具体可以参考这篇文章:传送门

另外,空类比较特殊(包括没有成员变量的类,因为成员函数是存在公共代码区的,不参与类大小的计算),空类的大小不是 0,编译器会给空类 1 个字节来唯一标识这个类的对象,因此空类的大小是 1 。

四、this 指针

1. 基本概念

在对象调用成员函数的时候,编译器会自动给函数传递对象的地址,当作被调函数的一个指针形参,这个指针就叫做this指针。该指针用于在成员函数中访问对象的成员变量。(由上文可知,对象只会存储自己的成员变量,成员函数时放在公共代码区的)

在这里插入图片描述

事实上,编译器给每个非静态的成员函数都隐藏了一个this指针参数。相比于 C 语言,调用成员函数时,我们不用自己传递对象的地址,编译器会帮我们完成。

2. 注意事项

this指针本质是一个常量指针,不能修改指向。

由于this指针是对象调用成员函数时,成员函数隐藏的一个指针形参,所以this指针的作用域是成员函数内部。

对象调用成员函数时,对象的地址作为实参传递给this形参。而作为一个形参,this指针应当存在函数栈帧中,有的编译器为了提高效率也会把this指针存在寄存器。

3. 经典习题

//1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->Print();return 0;
}

本题结果为正常运行。

在本题中,对象地址为空,所以对象调用成员函数的时候,传给成员函数this形参的是空指针。由于成员函数是存在公共代码区的,而不是存在对象中,所以对象地址为空并不影响调用成员函数。本题的成员函数内部,并没有对this形参的解引用,因此不存在对空指针解引用的问题,所以程序正常运行。

tips:程序里有空指针,编译是不会报错的,最多就是警告。所以我们写代码如果不小心对空指针解引用,编译是不会报错的,但是运行程序的时候就会崩溃。

//2.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:void PrintA(){cout << _a << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->PrintA();return 0;
}

本题结果为运行崩溃。

本题与上题的唯一区别在于,本题的成员函数内部访问了对象的成员变量,因此存在对this指针的解引用。而对象的地址为空,所以传给成员函数的this形参是空指针,因此出现了对空指针解引用的行为,程序运行崩溃。

4. 常见面试题

综上,我们就能回答两个常见的面试题。

this指针存在哪里:
this指针作为成员函数隐藏的形参,存在函数栈帧中,也有可能存在寄存器。

this指针可以为空吗:
可以,但是成员函数内不能访问对象的成员变量,即不能对this指针解引用。

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

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

相关文章

ubuntu docker离线安装docker(.deb包方式)(成功)(附卸载方法)

参考文章&#xff1a;Install Docker Engine on Ubuntu 文章目录 安装步骤下载安装包拷贝到目标主机并执行安装命令 验证拉取运行容器测试build dockerfile测试持久运行容器测试主机重启后&#xff0c;docker各服务是否正常自启 卸载方法附&#xff1a;各安装包作用说明&#x…

C++的类型转换运算符:static_cast

C的类型转换运算符&#xff1a;static_cast static_cast 用于在相关类型的指针之间进行转换&#xff0c;还可显式地执行标准数据类型的类型转换—这种转换原本将自动或隐式地进行。用于指针时&#xff0c; static_cast 实现了基本的编译阶段检查&#xff0c;确保指针被转换为相…

express编写一个简单的get接口

/01编写get接口.jsconst express require(express) const app express()// 创建路由 const useRouter require(./router/user.js) // 注册路由 app.use(/api,useRouter)app.listen(8080, (req, res) > {console.log(8080监听) }) ./02编写post接口 // 注意&#xff1a;如…

mac cli文件管理器

背景 最近研究了一下在控制台查看文件的插件ranger, 官方的解释是&#xff1a;一个cli下的文件管理器。觉得效果也很酷炫&#xff0c;所以在此展示一下。 安装 brew install ranger配置生成 建议第一次使用的时候使用 ranger --copy-configall将会在~/.config/ranger目录输…

VScode 避免逗号、括号时自动补全

设置项 控制是否应在遇到提交字符时接受建议。例如&#xff0c;在JavaScript中&#xff0c;半角分号(;)可以为提交字符&#xff0c;能够在接受建议的同时键入该字符。 "editor.acceptSuggestionOnCommitCharacter": false起因 比如打伪代码的时候输入一些缺少上下…

Solr原理剖析

一、简介 Solr是一个高性能、基于Lucene的全文检索服务器。Solr对Lucene进行了扩展&#xff0c;提供了比Lucene更为丰富的查询语言&#xff0c;并实现了强大的全文检索功能、高亮显示、动态集群&#xff0c;具有高度的可扩展性。同时从Solr 4.0版本开始&#xff0c;支持SolrCl…

22. 数据库的隔离级别和锁机制

文章目录 数据库的隔离级别和锁机制一、数据库隔离级别1. 隔离级别说明2. 如何选择隔离级别3. 查询当前客户端隔离级别的命令.4. 修改隔离的命令 二、数据库中的锁1. 共享锁、排他锁2. 死锁3. 行级锁、表级锁 三、解决更新丢失问题1. 解决方案2. 乐观锁、悲观锁3. 乐观锁、悲观…

STM32 CAN通讯实验程序

目录 STM32 CAN通讯实验 CAN硬件原理图 CAN外设原理图 TJA1050T硬件描述 实验线路图 回环实验 CAN头文件配置 CAN_GPIO_Config初始化 CAN初始化结构体 CAN筛选器结构体 接收中断优先级配置 接收中断函数 main文件 实验现象 补充 STM32 CAN通讯实验 CAN硬件原理图…

【RabbitMQ】之高可用集群搭建

目录 一、RabbitMQ 集群原理 1、默认集群原理2、镜像集群原理3、负载均衡方案 二、RabbitMQ 高可用集群搭建 1、RabbitMQ 集群搭建2、配置镜像队列3、HAProxy 环境搭建4、Keepalived 环境搭建 一、RabbitMQ 集群简介 1、默认集群原理 3-1、RabbitMQ 集群简介 单台 RabbitM…

vue项目中对组件使用v-model绑定值,在vue3中如何更新数据

在el-form 中 el-form-item 绑定组件进行校验 想在表单下面爆红提示 可以对组件使用v-model绑定值 vue2 通过this.$emit(‘input’,value) 更新 v-model值 vue3 通过this.$emit(‘update:modelValue’ ,value) 更新 v-model值

腾讯云CVM内存型服务器MA3、M6、M6ce和M5处理器CPU说明

腾讯云内存型CVM服务器CPU处理器大全&#xff0c;CVM内存型MA3、内存型M6、安全增强内存型M6ce、内存型M6p、内存型M5、MA2、M4、M3、M2、M1处理器主频、CPU性能性能大全说明&#xff0c;腾讯云内存型云服务器具有大内存的特点&#xff0c;适合高性能数据库、分布式内存缓存等需…

Settings系列(三)根据需求动态添加删除一级菜单、二级菜单的设置项

一 、背景 当时遇到定制需求,需要根据实际需要隐藏Settings的菜单项,于是开始了寻找方法 二 、准备工作 在看了一下源码,经过尝试后,确认生效后,就简单说明一下Settings中布局中主要组成元素 Settings中的菜单项是由 PreferenceScreen 和Preference组成的。其中Prefer…

Day7 C++ 指针

目录 什么是指针 指针变量的定义 指针变量定义语法 注意 指针所占内存空间 空指针 野指针 函数指针 声明函数指针 初始化函数指针 使用函数指针调用函数 指针的使用 const修饰指针 const修饰指针 --- 指针常量&#xff08;constant pointer&#xff09; const修…

libuv库学习笔记-advanced-event-loops

Advanced event loops libuv提供了非常多的控制event-loop的方法&#xff0c;你能通过使用多loop来实现很多有趣的功能。你还可以将libuv的event loop嵌入到其它基于event-loop的库中。比如&#xff0c;想象着一个基于Qt的UI&#xff0c;然后Qt的event-loop是由libuv驱动的&am…

会议OA项目之会议发布(一)

目录 前言&#xff1a; 会议发布的产品原型图&#xff1a; 1.会议发布 1.1实现的特色功能&#xff1a; 1.2思路&#xff1a; 使用的数据库&#xff1a; 我们要实现多功能下拉框的形式选择可以参考原文档&#xff1a;https://hnzzmsf.github.io/example/example_v4.html#down…

Michael.W基于Foundry精读Openzeppelin第14期——SafeMath.sol

Michael.W基于Foundry精读Openzeppelin第14期——SafeMath.sol 0. 版本0.1 SafeMath.sol 1. 目标合约2. 代码精读2.1 tryAdd(uint256 a, uint256 b) && trySub(uint256 a, uint256 b) && tryMul(uint256 a, uint256 b) && tryDiv(uint256 a, uint256 b…

php的设计模式有哪些

1&#xff0c;创建设计模式&#xff08;Creational Patterns&#xff09;(5种)&#xff1a; 用于创建对象时的设计模式。更具体一点&#xff0c;初始化对象流程的设计模式。当程序日益复杂时&#xff0c;需要更加灵活地创建对象&#xff0c;同时减少创建时的依赖。而创建设计模…

LlaMA2微调实战

LLaMA2-SFT LLaMA2-SFT, Llama-2-7B微调(transformers)/LORA(peft)/推理 Gtihub地址 https://github.com/yongzhuo/Llama2-SFT prompt text_1 f"".join(["[INST] <<SYS>>\n ""You are a helpful, respectful and honest assista…

数组专题攻破新学习笔记

数组专题攻破新学习笔记 1.移除有序数组中的重复项和移除元素2.二分查找需注意3.在排序数组中查找元素的第一个和最后一个位置4.最长回文串5.区域和检索-数组不可变 1.移除有序数组中的重复项和移除元素 思想一样但是细节不一样 思想一样就是 设置快慢指针&#xff0c;快指针…

ubuntu远程控制小车 运行rviz时报错

我买的是wheeltec的小车&#xff0c;测试rgbd相机时想在ubuntu上的rviz中显示小车的姿态和看到的rgb和depth图&#xff0c;但是ubuntu中rostopic list和rviz都找不到小车发布的话题信息&#xff0c;运行rqt_image_view时可以显示图片信息。 最终wheeltec的技术人员lucas帮我找了…