C++的明星之我是类001
文章目录
- 类
- 类定义格式
- 访问限定符
- 类域
- 实例化
- 实例化概念
- 对象大小
- this指针
- 两道nt题目
- 题目一
- 题目二
- C++和C语言实现stack对比
类
类定义格式
- 新增一个关键字
class,后加上类的名字,{}中为类的主体,类中的函数称为类的⽅法或者成员函数 - 定义在类⾯的成员函数默认为inline
访问限定符
- C++⼀种实现封装的⽅式,⽤类将对象的属性与⽅法结合在⼀块,让对象更加完善,通过访问权限选择性的将其接⼝提供给外部的⽤⼾使⽤
- 有三种访问限定符,public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访问,protected和private是⼀样的,以后继承章节才能体现出他们的区别
- 访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为⽌,如果后⾯没有访问限定符,作⽤域就到}即类结束
- ⼀般成员变量都会被限制为private/protected,需要给别⼈使⽤的成员函数会放为public
酱酱,到这里我们就可以看懂下面的代码啦
#include<iostream>
#include<assert.h>
using namespace std;
class Stack
{
public: // 共有就是说,客户可以使用咱们定义的方法void Init(int capacity = 4) // 感觉类让函数的实现更加方便,这里不需要写函数的参数,因为就是通过这个类型的变量来调用的这个方法{_array = (int*)malloc(sizeof(int) * capacity);if (nullptr == _array){perror("malloc申请空间失败");exit(1);}_capacity = capacity;_top = 0;}void Push(int x){_array[_top++] = x;}int Top(){assert(_array);return _array[_top - 1];}void Destroy(){free(top > 0);_array = nullptr;_top = _capacity = 0;}private: // 私有,就是说客户不能使用不能改变的东西//成员变量int* _array;size_t _capacity;size_t _top;
};int main()
{Stack st; // 类名就是对象(变量)类型st.Init(); // 和结构体一样,通过.操作符来访问类里的元素,这里就是类里的方法st.Push(1);st.Push(2);cout << st.Top() << endl;st.Destroy();
}
以上就是类的一个基本用法
C++中struct也可以定义类,C++兼容C中struct的⽤法,同时struct升级成了类,明显的变化是struct中可以定义函数,⼀般情况下我们还是推荐⽤class定义类
struct Person
{
public:void Init(const char* name, int age, int tel){strcpy(_name, name);_age = age;_tel = tel;}void Print(){cout << "姓名:" << _name << endl;cout << "年龄:" << _age << endl;cout << "电话:" << _tel << endl;}private:char _name[10];int _age;int _tel;
};int main()
{Person p;p.Init("zhangsan", 18, 13409873);p.Print();
}
class定义成员没有被访问限定符修饰时默认为private,struct默认为public
类域
- 类定义了⼀个新的作⽤域,类的所有成员都在类的作⽤域中,在类体外定义成员时(声明和定义分离),需要使⽤::作⽤域操作符指明成员属于哪个类域
实例化
实例化概念
- ⽤类类型在物理内存中创建对象的过程,称为类实例化出对象
- 类是对象进⾏⼀种抽象描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,⽤类实例化出对象时,才会分配空间
我们看下面代码
class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:// 这⾥只是声明,没有开空间int _year; int _month;int _day;
};int main()
{//Data::_year = 1; //err 这里的对象是类的一部分Date d1; // 类实例化出对象Date d2;d1.Init(2024, 3, 31);d1.Print();d2.Init(2024, 7, 5);d2.Print();return 0;
}
对象大小
首先我们思考的问题就是,在计算类的大小的是时候,要不要加上函数地址。结论是不需要加,只需要考虑内存对齐的问题,为什么呢?
我们想,如果两个对象都调用类里的同一个成员函数,这两个成员函数的地址是一样的,我们没有必要创建一个变量,就申请一片空间来存放函数的地址,这样会造成冗余,我们只用把这些方法都放在一个公共的地方,使用的时候直接用就行
而成员变量不一样,每一个对象的成员变量都不相同,所以每一个对象都只用为成员变量开辟空间
下面我们复习一下对齐规则
- 第⼀个成员在与结构体偏移量为0的地址处
- 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处
- 注意:对⻬数=编译器默认的⼀个对⻬数与该成员⼤⼩的较⼩值
- VS中默认的对⻬数为8
- 结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍
为啥要内存对齐
答:为了提高访问效率
看下面的实例

假设变量在内存中存储不对齐,也就是图中下面的存储方式,我们想要访问_i,就需要访问两次,因为计算机读取数据时是在一个整数倍读取的,比方说三十二位机器,一次就是读取四个字节的数据,且只能在4的整数倍位置读取数据,那么按照图中下面的存储方式,就要访问两次,而按照内存对齐的方式存储,只需要访问一次就可以读取到_i
我们再看一个实例
class A
{
public:void print(){}private:char _ch;int _i;
};class B
{void print(){}
};class C
{};int main()
{cout << sizeof(A) << endl; // 8cout << sizeof(B) << endl; // 1cout << sizeof(C) << endl; // 1 return 0;
}
对于没有成员变量的类,默认开一个字节的空间,起占位作用,不存储有效数据,表示对象存在
this指针
- 我们再返回去看一下Data类,现在就有一个疑问了,d1调⽤Init和Print函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?那么这⾥就要看到C++给了⼀个隐含的this指针解决这⾥的问题
- 编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this指针。⽐如Date类的Init的真实原型为,
void Init(Date* const this, int year, int month, int day)
所以调用的时候实际上是这样
d1.Iint(&d1, 2024,3, 31);
只不过指针是被省略掉的,所以实参的取地址也省略
- 类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值,this->_year = year;
- C++规定不能在实参和形参的位置显⽰的写this指针(编译时编译器会处理),但是可以在函数体内显⽰使⽤this指针
class Date
{
public: //不可以显示的加// void Init(Date* const this, int year, int month, int day)void Init(int year, int month, int day){// 编译报错:error C2106 : “ = ” :左操作数必须为左值// this = nullptr;// this->_year = year;_year = year;this->_month = month;this->_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;cout << this->_year << "/" << this->_month << "/" << this->_day << endl;//两种都可以}
private:// 这⾥只是声明,没有开空间int _year;int _month;int _day;
};
int main()
{// Date类实例化出对象d1和d2Date d1;Date d2;// d1.Init(&d1, 2024, 3, 31);d1.Init(2024, 3, 31);d1.Print();d2.Init(2024, 7, 5);d2.Print();return 0;
}
一个小问题:this指针存在于内存的哪个区域呢?
答案是存在于栈区,因为this是一个隐含的形参,形参就是函数的参数,函数参数存在于栈区
两道nt题目
题目一
class A
{
public:void Print(){cout << "A::Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}
A:编译报错 B:运行崩溃 C:正常运行
这个题答案选C
解析:A选项编译报错,说明是语法错误,首先排除,p虽然是一个空指针,且调用了函数Print,但是成员函数的地址没有存在于*p中,并且Print方法没有访问成员变量,所以不存在解引用,所以正常运行
题目二
class A
{
public:void Print(){cout << "A::Print()" << endl;cout << _a << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}
结果是运行崩溃
解析:cout << this->_a << endl相当于这样出现了解引用,所以程序崩溃
C++和C语言实现stack对比
C版
#define _CRT_SECURE_NO_WARNINGS 1
#include"stack_c.h"void STInit(ST* ps)
{assert(ps);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}void STDestroy(ST* ps)
{free(ps->a);ps->a = NULL;ps->capacity = ps->top = 0;
}void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->capacity == ps->top){//扩容int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");exit(1);}ps->a = tmp;ps->capacity = newcapacity;}ps->a[ps->top] = x;ps->top++;
}bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}void STPop(ST* ps)
{assert(ps);assert(!STEmpty(ps));ps->top--;
}STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->a[ps->top - 1];
}int main()
{ST st;STInit(&st);STPush(&st, 1);STPush(&st, 2);STPush(&st, 3);STPush(&st, 4);STPush(&st, 5);while (!STEmpty(&st)){printf("%d\n", STTop(&st));STPop(&st);}STDestroy(&st);return 0;
}
C++版
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<assert.h>
using namespace std;typedef int Datatype;
class stack
{
public:void Init(int n = 4){_a = (Datatype*)malloc(sizeof(Datatype) * n);if (_a == nullptr){perror("malloc fail");exit(1);}_capacity = 4;_top = 0;}void Push(int x){if (_capacity == _top){int newcapacity = _capacity * 2;Datatype* tmp = (Datatype*)realloc(_a, newcapacity *sizeof(Datatype));if (tmp == NULL){perror("realloc fail");return;}_a = tmp;_capacity = newcapacity;}_a[_top++] = x;}void Pop(){assert(_top > 0);--_top;}bool Empty(){return _top == 0;}int Top(){assert(_top > 0);return _a[_top - 1];}void Destroy(){free(_a);_a = nullptr;_top = _capacity = 0;}
private:Datatype* _a;int _capacity;int _top;
};int main()
{stack s;s.Init();s.Push(1);s.Push(2);s.Push(3);s.Push(4);while (!s.Empty()){printf("%d\n", s.Top());s.Pop();}s.Destroy();return 0;
}
完
相关文章:
C++的明星之我是类001
文章目录 类类定义格式访问限定符类域 实例化实例化概念对象大小 this指针两道nt题目题目一题目二 C和C语言实现stack对比 类 类定义格式 新增一个关键字class,后加上类的名字,{}中为类的主体,类中的函数称为类的⽅法或者成员函数定义在类⾯…...
深度学习与应用:行人跟踪
**实验 深度学习与应用:行人跟踪 ** ------ **1、 实验目的** ------ - 了解行人跟踪模型基础处理流程 - 熟悉行人跟踪模型的基本原理 - 掌握 行人跟踪模型的参数微调训练以及推理的能力 - 掌握行人跟踪模型对实际问题的应用能力,了解如何在特定的场景和…...
MySQL | DATE_ADD()函数
题1: 现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率。请你取出相应数据。 示例:question_practice_detail iddevice_idquest_idresultdate12138111wrong2021-05-0323214112wrong2021-05-0933214113wrong2021-06-1546543111right2021…...
DVWA 靶场环境搭建
作者:程序那点事儿 日期:2024/09/15 09:30 什么是DVWA: 是OWSASP官方编写的PHP网站,包含了各种网站常见漏洞(漏洞靶场),可以学习攻击及修复方式。 PHP环境包含了,Windows/Apache/Mysql/Php g…...
Autosar学习----AUTOSAR_SWS_BSWGeneral(七)
💥💥🔍 🔍 欢迎来到本博客❤️❤️💥💥 🐡优势:❤️博客内容尽量做到通俗易懂,逻辑清晰。 ⛳️座右铭:恒心,耐心,静心。 ⛳️ 欢迎一起…...
自动化测试框架集成:将Selenium集成到pytest与unittest中
目录 引言 一、Selenium简介 二、Selenium与pytest的集成 1. 安装pytest和Selenium 2. 编写测试用例 3. 运行测试 三、Selenium与unittest的集成 1. 编写测试类 2. 运行测试 四、Selenium自动化测试的最佳实践 1. 使用Page Object模式 2. 合理利用等待机制 3. 跨浏…...
华为GaussDB数据库(单机版)在ARM环境下的安装指南
一、软件版本 机器配置:8核16G,CPU: Huawei Kunpeng 920 2.9GHz操作系统:EulerOS 2.8 64bit with ARM数据库版本:GaussDB Kernel 505.1.0 build 44f4fa53 二、部署流程 2.1 新建用户 ① 以omm用户为例,添加一个omm用…...
计算机网络笔记002
### 课堂讨论对话 **学生A**: 老师,计算机网络的组成是怎样的?🤔 **老师**: 非常好的问题!计算机网络主要由硬件、软件和通信协议三部分组成。我们先从硬件开始讨论吧。 **学生B**: 硬件包括哪些设备呢?ὠ…...
Unity 的Event的Use()方法
对于Event的Use方法,其在调用后将不会再判断同类型的事件 这种情况下,第二个MosueDown不会进入,因为已经Use 如果把Use注释掉 依旧能进入第二个MosueDown 也就是说当使用了Use方法,相同的事件类型不会进第二遍...
数据分析师之Excel数据清洗
前言 目前,掌握一定的Excel技能时,怎么通过自己的技能实现数据分析的操作,就需要进行具体项目的实战,本身数据分析这个行业是非常吃经验的,既然我们是小白入坑,就需要多做实战演练,才能够实际的…...
手机解压软件加密指南:让文件更安全
在数字化时代,文件加密对于保护个人隐私和敏感信息的重要性不言而喻。随着互联网的飞速发展,我们的生活和工作越来越依赖于数字设备和网络。 然而,这也带来了一系列的安全风险,如黑客攻击、数据泄露等。文件加密技术成为了保护我…...
python yield generator 详解
目录 generator基础 generator应用 generator基础应用 generator高级应用 注意事项: 正文 本文将由浅入深详细介绍yield以及generator,包括以下内容:什么generator,生成generator的方法,generator的特点&#…...
MATLAB矩阵下标引用
在MATLAB中,普通的二维数组元素的数字索引分为双下标索引和单下标索引。双下标索引是通过一个二元数组对来对应元素在矩阵中的行列位置,例如A(2,3)表示矩阵A中第2行第3列的元素。单下标索引的方式是采用列元素优先的原则,对m行n列的矩阵按列排…...
syn洪水攻击原理是什么
在网络世界中,正常的网络访问就像一场有序的对话。当我们访问网站时,客户端与服务器要进行 TCP 三次握手来建立连接。首先,客户端向服务器发送一个 SYN 包,请求建立连接,这就如同向服务器打招呼说“我想连接”…...
前缀和(4)_除自身以外数组的乘积
个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 前缀和(4)_除自身以外数组的乘积 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌 目录…...
第二十一节:学习Redis缓存数据库的Hash操作(自学Spring boot 3.x的第五天)
这节记录下Redis的Hash操作。主要是opsForHash方式和boundHashOps方式。 boundHashOps和opsForHash都是Spring Data Redis中用于操作Redis哈希数据结构的方法,但它们在使用方式和场景上存在一些区别。 boundHashOps 使用方式: boundHashOps方法通过Redi…...
OpenCV视频I/O(1)视频采集类VideoCapture介绍
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 用于从视频文件、图像序列或摄像头捕获视频的类。 该类提供了用于从摄像头捕获视频或读取视频文件和图像序列的 C API。 以下是该类的使用方法&a…...
CVE-2024-46103
前言 CVE-2024-46103 SEMCMS的sql漏洞。 漏洞简介 SEMCMS v4.8中,SEMCMS_Images.php的search参数,以及SEMCMS_Products.php的search参数,存在sql注入漏洞。 (这个之前就有两个sql的cve,这次属于是捡漏了Ƕ…...
三,MyBatis-Plus 的各种查询的“超详细说明”,比如(等值查询,范围查询,模糊查询...)
三,MyBatis-Plus 的各种查询的“超详细说明”,比如(等值查询,范围查询,模糊查询…) 文章目录 三,MyBatis-Plus 的各种查询的“超详细说明”,比如(等值查询,范围查询,模糊查询...)1. …...
Linux 冯诺依曼体系结构与操作系统概念
目录 0.前言 1. 冯诺依曼体系结构概述 1.1 输入单元 1.2 中央处理单元(CPU) 1.3 输出单元 2. 冯诺依曼体系结构的关键特性 2.1 所有数据流向内存 2.2 数据流动示例:QQ聊天过程 3. 操作系统 3.1 概念 3.2 设计操作系统的目的 3.3 操作系统的“…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
Qt Quick Dialogs模块功能及架构
Qt Quick Dialogs 是 Qt Quick 的一个附加模块,提供了一套用于创建和使用系统对话框的 QML 类型。在 Qt 6.0 中,这个模块经过了重构和增强。 一、主要功能和特点 1. 对话框类型 Qt Quick Dialogs 在 Qt 6.0 中提供了以下标准对话框类型: …...
