织梦做的网站图片路径在哪/网络营销的背景和意义
【C++初阶】类和对象(上)
- 1.面向对象与面向过程的初步认识
- 2.类的引入
- 3. 类的定义
- 4.类的访问限定符及封装
- 4.1访问限定符
- 4.2封装
- 5.类的作用域
- 6.类的实例化
- 6.类的对象的大小计算
- 7.类的this指针
- 7.1this指针的引入
- 7.2this指针的一些特性

📃博客主页: 小镇敲码人
💞热门专栏:C++初阶
🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎
❤️ 什么?你问我答案,少年你看,下一个十年又来了 💞 💞 💞
1.面向对象与面向过程的初步认识
C++和C语言是不同的,C语言更关注过程,而C++关注更对象。
就好比我想把一头大象装进冰箱里面,C语言想要完成这件事需要先打开冰箱,然后把大象装进冰箱里面,这是具体的过程,C++并不关注具体的过程,C++会把整件事分为两个对象,冰箱和大象,靠对象之间的交互来完成这件事。
2.类的引入
在C语言中,我们学习了
struct
关键字所自定义的结构体类型,在C++中,我们在struct
里面不仅仅可以定义一些变量,而且可以定义函数,struct
升级变为了类。
我们在用C语言实现栈时,struct
里面只能定义变量,现在我们用C++实现栈,会发现它里面也可以定义函数:
typedef int DataTypeStack;struct Stack
{void init(size_t capacity){_array = (DataTypeStack*)malloc(sizeof(DataTypeStack)*capacity);if (nullptr == _array ){perror("malloc failed");exit(-1);}_size = 0;_capacity = capacity;}void push(DataTypeStack x){//满了就扩容if (_size == _capacity){_capacity *= 2;DataTypeStack* tmp = (DataTypeStack*)realloc(_array,sizeof(DataTypeStack) * _capacity);if (nullptr == tmp){perror("realloc failed");exit(-1);}_array = tmp;}_array[_size] = x;_size++;}DataTypeStack Top(){return _array[_size - 1];}void Destory(){free(_array);_array = nullptr;_size = 0;_capacity = 0;}DataTypeStack* _array;size_t _size;size_t _capacity;
};int main()
{Stack St;St.init(4);for (int i = 0; i < 10; i++){St.push(i);cout << St.Top() << endl;}St.Destory();return 0;
}
运行结果:
这样用起来是不是感觉比C语言里面的方便了很多呢?
3. 类的定义
虽然用
struct
也可以定义类,但是C++有了一个新的关键字class
来定义类,它们有所区别,我们稍后再谈这个问题。
class classname
{//类体:由成员变量和成员函数组成。
};
class
后面是类的名字,类里面的变量又叫做类的属性,类的成员变量,类里面的函数又叫做成员函数或者成员方法。
我们创建类通常有两种方式:
- 类的声明和定义都放在类里面,注意:声明和定义都放在类里面,编译器可能会将类里面的函数当成内联函数处理。
- 类的声明放在.h头文件里,类里面成员函数的定义放在.cpp文件里面,需要在成员函数前面加上
类名::
。
注意:我们在刷题的时候可以用第一种方式,但是以后工作了肯定是用第二中方式最佳。
关于类里面的成员变量的命名的建议:
class Date
{void init(int year, int month, int day){year = year;month = month;day = day;}int year;int month;int day;
};
这样看着就很抽象,你该如何区分我的成员变量和函数的形参呢?
所以外面应该这样写:
class Date
{void init(int year, int month, int day){_year = year;_month = month;_day = day;}int _year;int _month;int _day;
};
或者这样:
class Date
{void init(int year, int month, int day){year_ = year;month_ = month;day_ = day;}int year_;int month_;int day_;
};
具体看相应的要求,只要可以区分且易于知道成员变量的含义即可。
4.类的访问限定符及封装
4.1访问限定符
在类里面一般还有三个关键字,public
(公用)、private
(私有)、protected
(保护)。
class
里面不加访问限定符来修饰。里面的成员变量和成员函数默认是私有的,类外面访问是非法的。struct
里面不加访问限定符,默认里面的成员变量和成员函数是公有的,因为C++要兼容C语言。public
修饰表示公有在类外面可以访问,被private
和protected
修饰表示私有在类外面不能被访问,它们两个没有什么区别。- 访问限定符的作用域从一直从访问限定符出现的位置开始,到下一个访问限定符出现的位置结束。如果后面没有访问限定符了,那访问权限到
}
就结束了。
- 注意:访问限定符只在编译的时候有,当数据在内存里面时,没有这个概念。
C++struct
和class
的区别:
1.struct
里面默认的成员变量和函数是公有的,而class
里面默认的是私有的。
2. struct
可以定义结构体但是类不行,但是struct
可以用来定义类。
4.2封装
封装是类和对象的三大特性之一,其它的两大特性分别是:继承和多态。我们在类和对象阶段主要把封装搞清楚。
那什么是封装呢?
封装就是一种把数据和数据操作方法进行有机结合,把对象的属性和一些细节通过访问限定符的限制起来,只开放一些成员方法和外界进行交互。
就像我们使用电脑一样,电脑只对用户开放了USB接口,键盘、鼠标、显示器、开关机键,更重要的显卡、cpu则是封装起来了防止用户搞破坏,我们只需要使用它开放的一些工具就可以实现人机交互,C++的封装思想就类似于这个。
5.类的作用域
类定义了一个新的作用域,我们在类外面定义类里面的成员 函数时需要加上
类名::
。
下面一段代码,帮助你知道如何使用:
typedef int DataTypeStack;
class Stack
{
public:void init(size_t capacity);
private:DataTypeStack* _array;size_t _size;size_t _capacity;
};
void Stack::init(size_t capacity)
{_array = (DataTypeStack*)malloc(sizeof(DataTypeStack) * capacity);if (nullptr == _array){perror("malloc failed");exit(-1);}_size = 0;_capacity = 0;
}
这个类名::
是紧跟在成员函数名前面的,不能加空格,否则编译器就会报错,相当于告诉编译器,这个函数是给叫做stack
的类定义的。
6.类的实例化
类是对对象的描述,它就像建造一个工程所需要的图纸,是一个空格,是不占空间的,我们实例化对象的过程,就当于通过这个图纸建造房子了。
像如上代码,直接调用类里面的对象,没有实例化,是会报错的,这就像我们在C语言里面自定义了一个类型,但是没有用这个类型创建出一个变量那么我们就不能使用这个类型是一个道理。
我们想正确使用Stack
这个类,应该按如下代码:
typedef int DataTypeStack;
class Stack
{
public:void init(size_t capacity);
private:DataTypeStack* _array;size_t _size;size_t _capacity;
};
void Stack::init(size_t capacity)
{_array = (DataTypeStack*)malloc(sizeof(DataTypeStack) * capacity);if (nullptr == _array){perror("malloc failed");exit(-1);}_size = 0;_capacity = 0;
}int main()
{Stack ST;ST.init(4);return 0;
}
6.类的对象的大小计算
那学会了实例化对象,我们就应该思考类对象的大小是如何计算的呢?我们想计算类对象的大小,就必须搞清楚一个问题,我们可以创建很多相同类的对象,那这些类对象是如何在内存中存储的呢?
我们假设了三种方式:
- 每一个对象都有自己的成员变量和成员函数,它们都会保存一份。
- 每一个对象只保存自己的成员变量,成员函数放在一个公共的代码段。
到底结果如何我们可以用下面的代码来验证一下:
#include<iostream>
#include<stdlib.h>using namespace std;
//既有成员函数,又有成员变量
class c1
{void f1();int _a;
};//只有成员函数
class c2
{void f2();
};//空类,什么都没有class c3
{};int main()
{c1 A;c2 B;c3 C;cout << sizeof(A) << endl;cout << sizeof(B) << endl;cout << sizeof(C) << endl;return 0;
}
运行结果:
空类比较特殊,编译器给了一个字节来唯一标识这个类的对象,可以看到外面c2不是空类是有一个成员函数的,它也为1,说明类对象的存储方式应该是第二种,只保存成员变量,成员函数放在公共的代码段。
这里计算类对象大小的方法和计算结构体的大小是一样的,注意内存对齐规则即可。
7.类的this指针
7.1this指针的引入
我们先来定义一个Stack
的变量:
#include<iostream>
#include<stdlib.h>using namespace std;
typedef int DataTypeStack;class Stack
{
public:void init(size_t capacity){_array = (DataTypeStack*)malloc(sizeof(DataTypeStack)*capacity);if (nullptr == _array ){perror("malloc failed");exit(-1);}_size = 0;_capacity = capacity;}void push(DataTypeStack x){//满了就扩容if (_size == _capacity){_capacity *= 2;DataTypeStack* tmp = (DataTypeStack*)realloc(_array,sizeof(DataTypeStack) * _capacity);if (nullptr == tmp){perror("realloc failed");exit(-1);}_array = tmp;}_array[_size] = x;_size++;}DataTypeStack Top(){return _array[_size - 1];}void Destory(){free(_array);_array = nullptr;_size = 0;_capacity = 0;}
private:DataTypeStack* _array;size_t _size;size_t _capacity;
};int mian()
{Stack S1;Stack S2;S1.init(4);S2.init(8);return 0;
}
有这样一个问题,S1、S2都是调用公共代码段的函数init
,编译器该如何区分,是应该给S1的成员变量初始化呢,还是给S2的成员变量初始化呢?为了解决这个问题,C++引出了this指针的概念。
即:C++给每一个类的非静态成员函数,都隐式的添加了一个叫this
指针的参数,它保存该对象的地址,在函数里面访问对象里的成员变量,都是通过this
指针来访问的,只不过程序员不需要显式的写出来,这些都由编译器完成了。
7.2this指针的一些特性
- this指针的类型是
*const
,也就是说this保存的是对象的地址,这个地址是不能被改变的,否则,我们在成员函数里面就无法访问到对象的成员变量了。 - 只有在成员变量里面才能使用
this
指针。 this
本质是一个成员函数的一个形式参数,它的地址不保存在对象里面,当对象调用成员函数时将对象的地址传给this
指针,它是成员函数的第一个隐式的指针形参,不需要用户自己传,编译器通过ecx寄存器自动传了。
this指针可以为空吗?答案是可以的我们用下面的代码来验证:
#include<iostream>
#include<stdlib.h>using namespace std;
class c1
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};
int main()
{c1* ptr1 = nullptr;ptr1->Print();return 0;
}
这段代码的结果是什么呢?是正常运行还是崩溃呢?
可以看到程序是正常运行了的,有人可能有疑惑,ptr1
不是空指针吗,对其进行->
操作不是会导致程序崩溃吗,是的,但是这里编译器其实没有真正的对其进行->
操作,
因为我们调用这个Print函数和类对象的地址是无关的,函数保存在公共的代码段,这里的ptr1->Print()
操作只是起到了一个告诉编译器,Print函数是属于ptr1这个类对象的仅此而已,就相当我们在类外面定义类的成员函数要加类名::
是相同的道理,如果你不信我们可以转到反汇编看一下:
再看下面一段代码,它的运行结果又是如何呢?
#include<iostream>
#include<stdlib.h>using namespace std;
class c1
{
public:void Print(){cout << _a << endl;}
private:int _a;
};
int main()
{c1* ptr1 = nullptr;ptr1->Print();return 0;
}
运行结果:
这里程序crash了,我们应该知道,因为此时的this指针是一个空值,我们在Print函数里面访问_a,其实是this->_a
,只不过编译器帮助我们完成了这个工作了而已,当然只要形参和函数参数里面不显式的写出来就可以,在访问对象的成员变量时,是可以显式的写出this
指针的,这里对空指针进行->
操作显然是非法的,所以程序crash是必然的。
- 结论:
this
指针为空值,只要在调用的成员函数里面不使用this
指针访问成员变量,程序是不会crash的。
相关文章:

【C++初阶】类和对象(上)
【C初阶】类和对象(上) 1.面向对象与面向过程的初步认识2.类的引入3. 类的定义4.类的访问限定符及封装4.1访问限定符4.2封装 5.类的作用域6.类的实例化6.类的对象的大小计算7.类的this指针7.1this指针的引入7.2this指针的一些特性 📃博客主页…...

新版onenet平台安全鉴权的确定与使用
根据onenet官方更新的文档:平台提供开放的API接口,用户可以通过HTTP/HTTPS调用,进行设备管理,数据查询,设备命令交互等操作,在API的基础上,根据自己的个性化需求搭建上层应用。 为提高API访问安…...

容器核心技术-Namespace
一、容器 基于Linux 内核的 Cgroup, Namespace,以及Union FS等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术,由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。 1.1 容器主要特性…...

linux写文件如何保证落盘?
3.1.1. sync sync函数只是将所有修改过的块缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束。通常称为 update的系统守护进程会周期性地(一般每隔30秒)调用sync函数。这就保证了定期冲洗内核的块缓冲区。命令 sync也…...

2023 electron最新最简版打包、自动升级详解
这里我将讲解一下从0搭建一个electron最简版架子,以及如何实现打包自动化更新 之前我有写过两篇文章关于electron框架概述以及 常用api的使用,感兴趣的同学可以看看 Electron桌面应用开发 Electron桌面应用开发2 搭建electron 官方文档:ht…...

ConcurrentHashMap是如何实现线程安全的
目录 原理: 初始化数据结构时的线程安全 put 操作时的线程安全 原理: 多段锁cassynchronize 初始化数据结构时的线程安全 在 JDK 1.8 中,初始化 ConcurrentHashMap 的时候这个 Node[] 数组是还未初始化的,会等到第一次 put() 方…...

MYSQL:索引与锁表范围简述
一、聚簇索引原则 当有主键索引时,选择主键索引;如果没有主键索引,选择第一个的unique索引;如果都没有就选择隐藏生成的ROW_ID。 二、加锁原则 来自知乎MySQL探秘(七):InnoDB行锁算法 - 知乎 (zhihu.com) 在不通过索引条件查询时…...

15 款 PDF 编辑器帮助轻松编辑、合并PDF文档
PDF 编辑器在当今的数字环境中至关重要,因为 PDF 已成为共享和存储信息的首选格式。只需几分钟,可靠的 PDF 编辑器即可让用户能够根据其特定需求修改、定制和定制文档。在本文中,我们全面汇编了 15 款最佳免费 PDF 编辑器,让您可以…...

PS Raw中文增效工具Camera Raw 16
Camera Raw 16 for mac(PS Raw增效工具)的功能特色包括强大的图像调整工具。例如,它提供白平衡、曝光、对比度、饱和度等调整选项,帮助用户优化图像的色彩和细节。此外,Camera Raw 16的界面简洁易用,用户可…...

Flink源码解析二之执行计划⽣成
JobManager Leader 选举 首先flink会依据配置获取RecoveryMode,RecoveryMode一共两两种:STANDALONE和ZOOKEEPER。 如果用户配置的是STANDALONE,会直接去配置中获取JobManager的地址如果用户配置的是ZOOKEEPER,flink会首先尝试连接zookeeper,利用zookeeper的leadder选举服务发现…...

MySQL遍历所有表所有字段查找字符数据
MySQL遍历所有表所有字段查找字符数据 工作中有一些数据查找,但是在那个库那个表那个字段中并不明确,特别是敏感字符查找,如果数据量并不大,我们可以采用遍历整个库、表中字符来查找相关数据来解决该问题。 我们可以写一个存储过…...

Java中的异常处理机制是怎样的?
Java中的异常处理机制主要包括以下几个部分: 异常类(Exception Class):Java中的异常类继承自java.lang.Throwable,主要分为两大类:Error和Exception。Error表示程序无法处理的严重问题,如系统崩…...

高教社杯数模竞赛特辑论文篇-2023年A题:定日镜场的优化设计(附获奖论文及MATLAB代码实现)
目录 摘 要 一、 问题重述 1.1 问题背景 1.2 问题重述 二、 模型假设 三、 符号说明...

c语言实现http下载功能,显示进度条和下载速率
#include <stdio.h>//printf #include <string.h>//字符串处理 #include <sys/socket.h>//套接字 #include <arpa/inet.h>//ip地址处理 #include <fcntl.h>//open系统调用 #include <unistd.h>//write系统调用 #include <netdb.h>//…...
Educational Codeforces Round 157 (Rated for Div. 2) D. XOR Construction (思维题)
题目 给定长为n-1(n<2e5)的整数序列a,第i个数a[i](0<a[i]<2n) 构造一个长为n的整数序列b,满足: 1. 0到n-1在b数组中每个数恰好出现一次 2. 对于, 题目保证一定有解,有多组时可以输出任意一组 思路来源 …...

【unity实战】实现类似英雄联盟的buff系统
文章目录 先来看看最终效果前言开始BUFF系统加几个BUFF测试1. 逐层消失,升级不重置剩余时间的BUFF2. 一次性全部消失,升级重置剩余时间的BUFF3. 永久BUFF,类似被动BUFF4. 负面BUFF,根据当前BUFF等级计算每秒收到伤害值,…...

【C语言基础教程】函数指针与指针大小
文章目录 前言一、函数指针1.1 函数指针的概念1.2 三个示例代码示例1: 使用函数指针调用不同的函数示例 2: 使用函数指针实现回调函数示例 3: 使用函数指针数组 二、指针的大小2.1 前述2.2 指针大小如何决定?两方面理解 总结 前言 在C语言中,指针是一项…...

Web前端—网页制作(以“学成在线”为例)
版本说明 当前版本号[20231105]。 版本修改说明20231105初版 目录 文章目录 版本说明目录day07-学成在线01-项目目录02-版心居中03-布局思路04-header区域-整体布局HTML结构CSS样式 05-header区域-logo06-header区域-导航HTML结构CSS样式 07-header区域-搜索布局HTML结构CSS…...

Hive【Hive(八)自定义函数】
自定义函数用的最多的是单行函数,所以这里只介绍自定义单行函数。 Coding 导入依赖 <dependency><groupId>org.apache.hive</groupId><artifactId>hive-exec</artifactId><version>3.1.3</version></dependency>…...

linux远程桌面管理工具xrdp
一、概述 我们知道,我们日常通过vnc来远程管理linux图形界面,今天分享一工具Xrdp,它是一个开源工具,允许用户通过Windows RDP访问Linux远程桌面。 除了Windows RDP之外,xrdp工具还接受来自其他RDP客户端的连接…...

100天精通Python(可视化篇)——第106天:Pyecharts绘制多种炫酷桑基图参数说明+代码实战
文章目录 专栏导读一、桑基图介绍1. 桑基图是什么?2. 桑基图应用场景?二、桑基图配置选项1. 导包2. add函数3. 分层设置三、桑基图基础1. 普通桑基图2. 修改标签位置3. 修改节点布局方向4、月度开支桑基图书籍推荐专栏导读 🔥🔥本文已收录于《100天精通Python从入门到就…...

什么是OTP认证?OTP认证服务器有哪些应用场景?
OTP是一次性密码,即只能使用一次的密码。它基于专门的算法,每隔60秒生成一个不可预测的随机数字组合。这种密码的有效期仅在一次会话或交易过程中,因此不容易受到重放攻击。在计算器系统或其他数字设备上,OTP是一种只能使用一次的…...

shell_73.Linux使用新 shell 启动脚本
每次启动新 shell,bash shell 都会运行.bashrc 文件。①对此进行验证,可以使用这种方法:在 主目录下的.bashrc 文件中加入一条简单的 echo 语句,然后启动一个新 shell。 $ cat $HOME/.bashrc # .bashrc # Source global definiti…...

【领域驱动设计】聚合
从战术设计上,DDD 最值得借鉴的就是聚合根 什么是聚合 将实体和值对象在一致性边界之内组合聚合 这里的一致性包括 1、业务概念的完整性 2、业务规则的一致性:多个实体需要在一次操作中保持某种一致性(修改 A,同步必须修改 B&a…...

WiFi模块在智能家居中的应用与优化
智能家居技术的迅速发展已经改变了我们对家庭的定义。WiFi模块作为智能设备连接的核心,扮演着连接和控制智能家居生态系统的关键角色。本文将深入研究WiFi模块在智能家居中的应用,同时探讨如何通过优化来提升其性能和用户体验。 1. 智能家居中WiFi模块的…...

LeetCode75——Day27
文章目录 一、题目二、题解 一、题目 933. Number of Recent Calls You have a RecentCounter class which counts the number of recent requests within a certain time frame. Implement the RecentCounter class: RecentCounter() Initializes the counter with zero r…...

P6462补刀
灵光一现,突然就做出来了 正好写一下思路过程 一开始寻思是个数论的问题,貌似需要用到扩展欧几里得,不管那么多,直接写上,接着不断缝缝补补修修改改,此处省略一小时.... 做不出来....好难受 星期天,无聊,做个题.. 突然,不对啊 这个题实际上不就是我当前打还是不打的一个选…...

Python教程---Python交互界面
当我们通过命令行来输入Python,所进入到的界面就是Python的交互界面 结构: 版本和版权声明: Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 16:07:46) [MSC v.1900 32 bit (Intel)] on win32 Type "help", "copyright"…...

基于计算机视觉的身份证识别系统 计算机竞赛
0 前言 🔥 优质竞赛项目系列,今天要分享的是 基于机器视觉的身份证识别系统 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-sen…...

[python] logging输出到控制台(标准输出)
要将logging.info输出到控制台(标准输出),可以使用以下代码: import logging# 创建一个logger对象 logger logging.getLogger(__name__)# 创建一个控制台处理器 console_handler logging.StreamHandler()# 设置控制台处理器的输…...