当前位置: 首页 > news >正文

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&#xff0c;后加上类的名字&#xff0c;{}中为类的主体&#xff0c;类中的函数称为类的⽅法或者成员函数定义在类⾯…...

深度学习与应用:行人跟踪

**实验 深度学习与应用&#xff1a;行人跟踪 ** ------ **1、 实验目的** ------ - 了解行人跟踪模型基础处理流程 - 熟悉行人跟踪模型的基本原理 - 掌握 行人跟踪模型的参数微调训练以及推理的能力 - 掌握行人跟踪模型对实际问题的应用能力&#xff0c;了解如何在特定的场景和…...

MySQL | DATE_ADD()函数

题1&#xff1a; 现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率。请你取出相应数据。 示例&#xff1a;question_practice_detail iddevice_idquest_idresultdate12138111wrong2021-05-0323214112wrong2021-05-0933214113wrong2021-06-1546543111right2021…...

DVWA 靶场环境搭建

作者&#xff1a;程序那点事儿 日期&#xff1a;2024/09/15 09:30 什么是DVWA: 是OWSASP官方编写的PHP网站&#xff0c;包含了各种网站常见漏洞&#xff08;漏洞靶场&#xff09;&#xff0c;可以学习攻击及修复方式。 PHP环境包含了&#xff0c;Windows/Apache/Mysql/Php g…...

Autosar学习----AUTOSAR_SWS_BSWGeneral(七)

&#x1f4a5;&#x1f4a5;&#x1f50d; &#x1f50d; 欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f421;优势&#xff1a;❤️博客内容尽量做到通俗易懂&#xff0c;逻辑清晰。 ⛳️座右铭&#xff1a;恒心&#xff0c;耐心&#xff0c;静心。 ⛳️ 欢迎一起…...

自动化测试框架集成:将Selenium集成到pytest与unittest中

目录 引言 一、Selenium简介 二、Selenium与pytest的集成 1. 安装pytest和Selenium 2. 编写测试用例 3. 运行测试 三、Selenium与unittest的集成 1. 编写测试类 2. 运行测试 四、Selenium自动化测试的最佳实践 1. 使用Page Object模式 2. 合理利用等待机制 3. 跨浏…...

华为GaussDB数据库(单机版)在ARM环境下的安装指南

一、软件版本 机器配置&#xff1a;8核16G&#xff0c;CPU: Huawei Kunpeng 920 2.9GHz操作系统&#xff1a;EulerOS 2.8 64bit with ARM数据库版本&#xff1a;GaussDB Kernel 505.1.0 build 44f4fa53 二、部署流程 2.1 新建用户 ① 以omm用户为例&#xff0c;添加一个omm用…...

计算机网络笔记002

### 课堂讨论对话 **学生A**: 老师&#xff0c;计算机网络的组成是怎样的&#xff1f;&#x1f914; **老师**: 非常好的问题&#xff01;计算机网络主要由硬件、软件和通信协议三部分组成。我们先从硬件开始讨论吧。 **学生B**: 硬件包括哪些设备呢&#xff1f;&#x1f60…...

Unity 的Event的Use()方法

对于Event的Use方法&#xff0c;其在调用后将不会再判断同类型的事件 这种情况下&#xff0c;第二个MosueDown不会进入&#xff0c;因为已经Use 如果把Use注释掉 依旧能进入第二个MosueDown 也就是说当使用了Use方法&#xff0c;相同的事件类型不会进第二遍...

数据分析师之Excel数据清洗

前言 目前&#xff0c;掌握一定的Excel技能时&#xff0c;怎么通过自己的技能实现数据分析的操作&#xff0c;就需要进行具体项目的实战&#xff0c;本身数据分析这个行业是非常吃经验的&#xff0c;既然我们是小白入坑&#xff0c;就需要多做实战演练&#xff0c;才能够实际的…...

手机解压软件加密指南:让文件更安全

在数字化时代&#xff0c;文件加密对于保护个人隐私和敏感信息的重要性不言而喻。随着互联网的飞速发展&#xff0c;我们的生活和工作越来越依赖于数字设备和网络。 然而&#xff0c;这也带来了一系列的安全风险&#xff0c;如黑客攻击、数据泄露等。文件加密技术成为了保护我…...

python yield generator 详解

目录 generator基础 generator应用 generator基础应用   generator高级应用 注意事项&#xff1a; 正文 本文将由浅入深详细介绍yield以及generator&#xff0c;包括以下内容&#xff1a;什么generator&#xff0c;生成generator的方法&#xff0c;generator的特点&#…...

MATLAB矩阵下标引用

在MATLAB中&#xff0c;普通的二维数组元素的数字索引分为双下标索引和单下标索引。双下标索引是通过一个二元数组对来对应元素在矩阵中的行列位置&#xff0c;例如A(2,3)表示矩阵A中第2行第3列的元素。单下标索引的方式是采用列元素优先的原则&#xff0c;对m行n列的矩阵按列排…...

syn洪水攻击原理是什么

在网络世界中&#xff0c;正常的网络访问就像一场有序的对话。当我们访问网站时&#xff0c;客户端与服务器要进行 TCP 三次握手来建立连接。首先&#xff0c;客户端向服务器发送一个 SYN 包&#xff0c;请求建立连接&#xff0c;这就如同向服务器打招呼说“我想连接”&#xf…...

前缀和(4)_除自身以外数组的乘积

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 前缀和(4)_除自身以外数组的乘积 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录…...

第二十一节:学习Redis缓存数据库的Hash操作(自学Spring boot 3.x的第五天)

这节记录下Redis的Hash操作。主要是opsForHash方式和boundHashOps方式。 boundHashOps和opsForHash都是Spring Data Redis中用于操作Redis哈希数据结构的方法&#xff0c;但它们在使用方式和场景上存在一些区别。 boundHashOps 使用方式&#xff1a; boundHashOps方法通过Redi…...

OpenCV视频I/O(1)视频采集类VideoCapture介绍

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 用于从视频文件、图像序列或摄像头捕获视频的类。 该类提供了用于从摄像头捕获视频或读取视频文件和图像序列的 C API。 以下是该类的使用方法&a…...

CVE-2024-46103

前言 CVE-2024-46103 SEMCMS的sql漏洞。 漏洞简介 SEMCMS v4.8中&#xff0c;SEMCMS_Images.php的search参数&#xff0c;以及SEMCMS_Products.php的search参数&#xff0c;存在sql注入漏洞。 &#xff08;这个之前就有两个sql的cve&#xff0c;这次属于是捡漏了&#x1f6…...

三,MyBatis-Plus 的各种查询的“超详细说明”,比如(等值查询,范围查询,模糊查询...)

三&#xff0c;MyBatis-Plus 的各种查询的“超详细说明”&#xff0c;比如(等值查询&#xff0c;范围查询&#xff0c;模糊查询…) 文章目录 三&#xff0c;MyBatis-Plus 的各种查询的“超详细说明”&#xff0c;比如(等值查询&#xff0c;范围查询&#xff0c;模糊查询...)1. …...

Linux 冯诺依曼体系结构与操作系统概念

目录 0.前言 1. 冯诺依曼体系结构概述 1.1 输入单元 1.2 中央处理单元&#xff08;CPU&#xff09; 1.3 输出单元 2. 冯诺依曼体系结构的关键特性 2.1 所有数据流向内存 2.2 数据流动示例&#xff1a;QQ聊天过程 3. 操作系统 3.1 概念 3.2 设计操作系统的目的 3.3 操作系统的“…...

UE4中 -skipbuild -nocompile 有什么区别

在项目开发中&#xff0c;我看到了在调用 Engine\\Build\\BatchFiles\\RunUAT.bat 相关的命令行中&#xff0c;有 -skipbuild、 -nocompile 两个很像的参数&#xff0c;于是想探究一下它们的区别与含义。 -skipbuild 参数 到底有没有 -skipbuild 这个参数&#xff1f;根据 http…...

k8s篇之数据挂载类型及区别

一、K8S集群数据挂载类型及区别 在 Kubernetes 中,数据挂载类型主要有以下几种,每种类型适用于不同的场景。以下是主要的挂载类型及其应用场景的详细说明: 1. emptyDir 描述:emptyDir 是一个空目录,其生命周期与 Pod 相同。 它在 Pod 创建时被创建,并在 Pod 删除时被清…...

LiveQing视频点播流媒体RTMP推流服务功能-支持电子放大拉框放大直播视频拉框放大录像视频流拉框放大电子放大

LiveQing视频点播流媒体RTMP推流服务功能-支持电子放大拉框放大直播视频拉框放大录像视频流拉框放大电子放大 1、鉴权直播2、视频点播3、RTMP推流视频直播和点播流媒体服务 1、鉴权直播 鉴权直播-》播放 &#xff0c;左键单击可以拉取矩形框&#xff0c;放大选中的范围&#x…...

fetch怎么使用

fetch 是一个现代、强大的、基于 Promise 的网络请求 API&#xff0c;用于在浏览器中发起网络请求&#xff08;如异步获取资源&#xff09;。它提供了一种更加简洁和灵活的方式来替代 XMLHttpRequest。下面是 fetch 的基本使用方法和一些示例。 基本语法 fetch(url, options)…...

回归预测 | Matlab基于SO-SVR蛇群算法优化支持向量机的数据多输入单输出回归预测

回归预测 | Matlab基于SO-SVR蛇群算法优化支持向量机的数据多输入单输出回归预测 目录 回归预测 | Matlab基于SO-SVR蛇群算法优化支持向量机的数据多输入单输出回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab基于SO-SVR蛇群算法优化支持向量机的数据多…...

光耦知识分享:如何挑选合适的可控硅光耦型号

可控硅光耦是一种光电耦合器件&#xff0c;它结合了光敏元件&#xff08;通常是光敏二极管&#xff09;和可控硅器件&#xff08;如普通可控硅或三端可控硅&#xff09;的特性。它的工作原理是利用光信号控制可控硅的导通和截止&#xff0c;从而实现对电路的控制。 可控硅光耦…...

MySql Explain优化命令使用

MySql Explain优化命令使用 truncate table student // 自增id 从 0 开始 delete from student // 自增id 会保留 &#xff0c; 108 区别&#xff1a; 1&#xff1a;自增id 2&#xff1a;delete 可以恢复 truncate 无法恢复 前言 EXPLAIN 是一个用于获取 SQL 语句执行计划的…...

Android NestedScrollView+TabLayout+ViewPager+ 其它布局,ViewPager 不显示以及超出屏幕不显示问题

前言 此场景为 NestedScrollView 嵌套多个布局 &#xff0c;大致结构为 NestedScrollViewTabLayoutViewPagerfragment 其它View,如下图 &#xff0c; 一、ViewPager 设置高度才会显示内容问题 原因&#xff1a;NestedScrollView 计算高度先于 ViewPager 渲染前&#xff0c;所…...

Linux开机logo设置

本文介绍Linux开机logo设置。 常用的Linux开机logo设置工具有fbi(Linux Framebuffer Imageviewer)&#xff0c;plymouth等&#xff0c;本文针对fbi工具进行开机logo设置。 1.fbi工具安装 命令行下&#xff0c;输入&#xff1a; sudo apt-get install fbi -y 安装完毕后&am…...

webpack插件开发 模拟vue系统登录后,获取a标签下的文件

浏览器插件开发中&#xff0c;在webpack插件开发中&#xff0c;模拟Vue系统登录后获取a标签下的文件&#xff0c;可以通过监听某个登录事件&#xff0c;并在事件处理函数中修改Webpack的输出配置来实现。以下是一个简化的示例代码&#xff1a; // 假设有一个插件构造函数 Logi…...