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

【C++初阶】类与对象(一)

目录

  • 1、初识面向对象思想
  • 2、类 struct
    • 2.1 C++中的struct及使用
  • 3、类 class
    • 3.1 类的定义
    • 3.2 类的访问限定符
      • 3.2.1 访问限定符是什么
      • 3.2.2 访问限定符的使用
      • 3.2.3 访问限定符的使用规范
      • 3.2.4 访问限定符与封装
    • 3.3 类做声明和定义分离
      • 3.3.1 声明和定义分离
      • 3.3.2 在函数声明的地方也可定义
    • 3.4 类的作用域
      • 3.4.1 类的成员变量命名规范
      • 3.4.1 类里支持重载
  • 4、类的实例化
    • 4.1 类的实例化是什么
    • 4.1 为什么有类的实例化
      • 4.1.1 类与对象的关系
  • 5、计算类的对象大小
    • 5.1 结构体内存对齐规则
    • 5.2 空类
    • 5.3 类对象存储方式
  • 6、关键字this指针
    • 6.1 this指针是什么
    • 6.2 this指针的特性
    • 6.3 练习
      • 6.3.1 题一
      • 6.3.2 题二

1、初识面向对象思想

C语言是面向过程的,将问题分解成多个步骤,通过函数调用一个一个解决。C++是在C语言的基础上增加了面向对象的思想,关注的是对象,将问题分成不同的对象,依靠对象之间交互完成的。

以洗衣服为例:
C语言: 洗衣服分为多个步骤逐一完成。
在这里插入图片描述
C++: 对象有人、衣服、洗衣粉和洗衣机,通过它们之间的交互完成。
在这里插入图片描述

2、类 struct

2.1 C++中的struct及使用

对于struct大家并不陌生,在C语言中它是用来定义一个结构体的关键字。如下表示栈:

typedef struct Stack
{int* a;int top;int capacity;
}Stack;
//声明
void StackPush(Stack* ps, int x);
void StackInit(Stack* ps);
//定义
void StackInit(Stack* ps)
{//...
}
void StackPush(Stack* ps, int x)
{//....
}int main()
{Stack st;StackInit(&st);StackPush(&st, 1);return 0;
}

C++创始人对以上这种写法感觉很繁琐,所以对struct进行了升级,变成了类。struct定义的类名就是类型,且可以在类里定义函数。
如下:

struct Stack
{int* a;int top;int capacity;void Init(){//...}void Push(int x){//....}
};int main()
{Stack st;//类名就是类型,前面不需要加structst.Init();st.Push(1);return 0;
}

这样写是不是比前面C语言的代码简洁了不少。当然,通常来说C++很少使用struct ,使用class比较多。

3、类 class

3.1 类的定义

class className
{
//
// 类体:由成员函数和成员变量组成
//
}; // 一定要注意后面的分号,与C语言的结构体同

class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。

3.2 类的访问限定符

3.2.1 访问限定符是什么

类一共有3个访问限定符,分别是:

public(公有)、protected(保护)、private(私有)

访问限定符是用来指定类中的成员或者函数是否可在类外被访问的关键字。它是C++实现封装的方式,同时让代码看起来更加完善。

3.2.2 访问限定符的使用

使用访问限定符先得知道它们的特性:

public(公有):修饰的成员在类外可以直接被访问
protected(保护) 和private(私有):在类外不能直接被访问。(在这里protected和private的功能是类似的)
访问限定符的作用域从当前开始到出现下一个访问限定符结束,如果后面没有其他访问限定符,类结束就是该访问限定符的作用域结束

struct Stack
{
private://私有int* a;int top;int capacity;
public://公有void Init(){//...}void Push(int x){//....}
};
int main()
{Stack st;st.Init();st.Push(1);return 0;
}

类里面的成员函数是公有的,所以类外可以访问到;成员变量是私有的,类外不能被访问。
在这里插入图片描述

3.2.3 访问限定符的使用规范

一般情况下,我们看到的C++代码中的类里面都有访问限定符,比如private和public。大家可能有一个疑惑,访问限定符非写不可吗?其实不是。不写访问限定符也是有区别的,只不过这个区别是在class和struct两个关键字上。class不写访问限定符,默认的访问权限是private;struct不写访问限定符,默认的访问权限是public。这同时也说明了为什么使用struct时类外都可以访问到里面的成员,因为C++要兼容C语言。但是,为了防止错误发生,尽量写访问限定符,这样同时也让代码比较规范。

3.2.4 访问限定符与封装

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互
封装本质上是一种管理,让用户更方便使用类
在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。

就好比用户使用电脑,只要操作键盘、鼠标和开关机即可,不必知道电脑内部是如何设计的。

3.3 类做声明和定义分离

3.3.1 声明和定义分离

类的定义有两种写法,一种是声明和定义全部写在类里,另一种是分文件声明和定义分离,在做项目的时候或者代码规模较大以后者居多。

#include <iostream>
using namespace std;
class Stack
{
private:int* a;int top;int capacity;
public:void Init();void Push(int x);
};
/
void Stack::Init()
{//...
}
void Stack::Push(int x)
{//...
}
/
int main()
{Stack st;st.Init();st.Push(1);return 0;
}

定义函数的文件里函数名加上Stack:: 是为了找到Stack类里的函数,因为如果头文件里不止有栈的初始化的声明,可能也有其他的,比如队列的初始化的声明。

3.3.2 在函数声明的地方也可定义

C++是可以声明和定义混着写的
比如:

class Stack
{
private:int* a;int top;int capacity;
public:void Init();void Push(int x){//...}
};

要注意的一点,定义写在声明里函数变成了内联函数。但是也并不完全是内联函数,因为是否是内联函数取决于编译器。一般来说,声明里定义函数最好是代码比较少的,少的写在声明里可以变成内联函数,提高程序运行效率。

3.4 类的作用域

3.4.1 类的成员变量命名规范

我们在写类的成员变量命名时,要注意规范性。
如下:

class Date
{
private:int year;int month;int day;
public:void Init(int year, int month, int day){year = year;month = month;day = day;}void Print(){cout << year << "-" << month << "-" << day << endl;}
};

成员变量分别是year、month、day,但是传进来的参数的名字也是year、month、day,赋值的时候是不是感觉很乱。所以建议这样写更好:

class Date
{
private:int _year;int _month;int _day;
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
};
int main()
{Date d1;d1.Init(2023, 10, 23);d1.Print();return 0;
}

在这里插入图片描述
成员变量前面加个下划线就好区分了。这里不一定是前面加下划线,后面加或者其他方式都行,只要能够区别参数的名字即可。

3.4.1 类里支持重载

一个类就是一个作用域,是支持重载的

class Date
{
private:int _year;int _month;int _day;
public:void Init(){_year = 2020;_month = 1;_day = 1;}void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
};
int main()
{Date d1;d1.Init();d1.Print();return 0;
}

在这里插入图片描述

4、类的实例化

4.1 类的实例化是什么

类创建对象的过程就叫做类的实例化。类是对对象进行描述的,它限定了类里面有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。

    Date d1;
// 类 + 对象

4.1 为什么有类的实例化

类里面的成员变量是声明,它没有实际的空间,不能存储数据,必须先要实例化才行。

4.1.1 类与对象的关系

一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。类可以比作一张建筑物的图纸,对象就是具体的建筑物,图纸总不能居住吧,但是具体的建筑可以。
在这里插入图片描述

5、计算类的对象大小

5.1 结构体内存对齐规则

计算类的对象大小之前,我们先来回顾下C语言学过的内存对齐规则:

1.第一个成员在与结构体偏移量为0的地址
2.某个成员变量的对齐数 = 编译器默认的对齐数 和 该成员变量大小 中的较小值
3.前面的成员变量的对齐数要是当前成员变量的对齐数的整数倍
4.结构体总大小 = 最大对齐数的整数倍
5.如果结构体嵌套结构体,里面的结构体还是以上步骤进行。外面的结构体也是一样的,只不过整体的总大小是最大对齐数的整数倍,最大对齐数可能是嵌套的结构体的大小。

class A
{int year;int month;int day;
};
class B
{char y;int t;
};
int main()
{A a;B b;cout << sizeof(a) << endl;cout << sizeof(b) << endl;return 0;
}

在这里插入图片描述

5.2 空类

空类是没有成员变量的类
比如:

class A
{};
int main()
{A a;cout << sizeof(a) << endl;return 0;
}

a的大小是:
在这里插入图片描述
无成员变量的类编译器给一个字节,只是标记它的对象存在而已。

5.3 类对象存储方式

先来看一个例子:

class A
{};
class B
{void Func(){}
};
int main()
{A a;B b;cout << sizeof(a) << endl;cout << sizeof(b) << endl;return 0;
}

运行结果:
在这里插入图片描述
我们知道,只要是无成员变量的类都是给一个字节,但是为什么有成员函数却不算进去呢?这与类对象的存储方式有关。

每个对象的成员变量是不同的,但是调用同一个函数。如果类创建多个对象,那么每个对象都要保存一份相同的代码,这样就会浪费空间。所以对象里面只保存成员变量的代码,成员函数放在公共代码段。就好比一间教室有50个学生,每个学生有自己的课本和笔,但是总不能给每个学生安排一个老师吧。

6、关键字this指针

6.1 this指针是什么

先来看一段代码:

class Date
{
private:int _year;int _month;int _day;
public:void Func(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
};
int main()
{Date d1;Date d2;d1.Func(2023, 10, 23);d1.Print();d2.Func(2020, 1, 3);d2.Print();return 0;
}

运行结果:
在这里插入图片描述
这里设置了两个对象d1和d2,它们调用的是同一个成员函数,问题是函数是怎么知道应该使用哪个对象(怎么找到对象的)

C++引入了this指针解决了这个问题,this指针是一个成员函数隐藏的形参,对象在调用成员函数时,将对象的地址传给this指针,对成员变量的操作都需要该指针访问。只不过不需要用户自己写出来,C++编译器自动完成。

	*void Print(Date* this){cout << this->_year << "-" << this->_month << "-" << this->_day << endl;}///d1.Print(&d1);d2.Print(&d2);

6.2 this指针的特性

  1. this指针的类型:类类型* const
  2. 只能在“成员函数”的内部使用

this指针存在哪里
this指针是一个形参,存在栈上,但是VS存在ecx寄存器下,不同的编译器可能不同。

this指针可以为空吗
可以为空,但是有些情况不能为空。调用函数时如果函数内部不需要通过this指针指向当前对象且对其进行操作时可以为空,否则会报错。

6.3 练习

6.3.1 题一

该程序运行结果是~~

class A
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}

答案:正常运行
在这里插入图片描述
分析:
p是空指针,很多人以为是空指针然后加箭头就是运行错误,这里不是。Print函数不在对象里,p的作用首先是创建对象,然后检查Print这个成员函数是否在这个类里面。没有,运行错误;反之,正常运行。

6.3.2 题二

该程序运行结果是~~

class A
{
public:void PrintA(){cout << _a << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->PrintA();return 0;
}

答案:运行崩溃
分析:
这题与上题的代码基本类似,只不过成员函数里要打印的是 _a ,p是空指针,传参给this指针也是空指针,打印 _a 不就对空指针解引用了吗,会导致程序运行崩溃。

相关文章:

【C++初阶】类与对象(一)

目录 1、初识面向对象思想2、类 struct2.1 C中的struct及使用 3、类 class3.1 类的定义3.2 类的访问限定符3.2.1 访问限定符是什么3.2.2 访问限定符的使用3.2.3 访问限定符的使用规范3.2.4 访问限定符与封装 3.3 类做声明和定义分离3.3.1 声明和定义分离3.3.2 在函数声明的地方…...

thinkPHP框架详解+部署

目录 什么是ThinkPHP: ThinkPHP的主要特性&#xff1a; 什么是ThinkPHP: ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架&#xff0c;诞生于2006年初&#xff0c;由国内的技术爱好者创建&#xff0c;遵循Apache2开源协议发布&#xff0c;是为了敏捷WEB应用开发和…...

Java拦截器(Interceptor)和过滤器(Filter)实例详解

一、Java过滤器和拦截器 1.1、过滤器(Filter) Filter过滤器&#xff0c;是Servlet&#xff08;Server Applet&#xff09;技术中的技术&#xff0c;开发人员可以通过Filter技术&#xff0c;管理web资源&#xff0c;可以对指定的一些行为进行拦截&#xff0c;例如URL级别的权限…...

通过热敏电阻计算温度(二)---ODrive实现分析

文章目录 通过热敏电阻计算温度&#xff08;二&#xff09;---ODrive实现分析测量原理图计算分析计算拟合的多项式系数根据多项式方程计算温度的函数温度计算调用函数 通过热敏电阻计算温度&#xff08;二&#xff09;—ODrive实现分析 ODrive计算热敏电阻的温度采用的时B值的…...

基于typescript+express实现一个简单的接口权限验证

package.json "scripts": {"start": "nodemon src/main.ts","start:a": "nodemon src/a.ts","build": "tsc","build:dev": "tsc src/main.ts"}, express服务器文件 import * as…...

yolov7改进优化之蒸馏(二)

续yolov7改进优化之蒸馏&#xff08;一&#xff09;-CSDN博客 上一篇已经基本写出来yolov7/v5蒸馏的整个过程&#xff0c;不过要真的训起来我们还需要进行一些修改。 Model修改 蒸馏需要对teacher和student网络的特征层进行loss计算&#xff0c;因此我们forward时要能够返回需…...

生产与作业管理(POM)的历史

1800年&#xff0c;惠特尼&#xff1a;零件标准化、质量管理。 1881年&#xff0c;泰勒&#xff1a;人员选拔、计划和时程安排、动作研究。管理与劳动分开。 - 使雇员与工作相适应。 - 提供适当的训练。 - 提供正确的工作方法和工具。 - 建立适当的激励机制促使工作得以完成。 …...

交换机基础(二)

一、VLAN 基础知识 虚拟局域网 (Virtual Local Area Network,VLAN) 是一种将局域网设 备从逻辑上划分成一个个网段&#xff0c;从而实现虚拟工作组的数据交换技术。 这一技术主要应用于3层交换机和路由器中&#xff0c;但主流应用还是在3层交换机中。 VLAN 是基于物理网络上构建…...

回归预测 | MATLAB实现基于BP-Adaboost的BP神经网络结合AdaBoost多输入单输出回归预测

回归预测 | MATLAB实现基于BP-Adaboost的BP神经网络结合AdaBoost多输入单输出回归预测 目录 回归预测 | MATLAB实现基于BP-Adaboost的BP神经网络结合AdaBoost多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于BP-Adaboost的BP…...

【蓝桥每日一题]-动态规划 (保姆级教程 篇11)#方格取数2.0 #传纸条

目录 题目&#xff1a;方格取数 思路&#xff1a; 题目&#xff1a;传纸条 思路&#xff1a; 题目&#xff1a;方格取数 &#xff08;跑两次&#xff09; 思路&#xff1a; 如果记录一种方案后再去跑另一个方案&#xff0c;影响因素太多了&#xff0c;所以两个方案要同时开…...

前端TypeScript学习day05-索引签名、映射与类型声明文件

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 索引签名类型 映射类型 索引查询&#xff08;访问&#xff09;类型 基本使用 同时查询多个索引的类型…...

Echarts柱状图数据过多设置滚动条效果

未设置前&#xff1a; 设置后&#xff1a; dataZoom: [ { show: true, height:8, bottom:0, startValue: 0, //起始值 endValue: 5, //结束值 showDetail: fals…...

64 最长公共子序列

最长公共子序列 题解1 DP 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的 最长公共子序列的长度。如果不存在 公共子序列&#xff0c;返回 0 。 一个字符串的子序列是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些…...

matlab常用函数

绘图函数 一、plot()&#xff1a;二维图形绘制 1、plot(y)&#xff1a; 对于只含一个输入参数的plot函数&#xff0c;如果输入参数y为向量&#xff0c;则以该参数为纵坐标&#xff0c;横坐标从1开始至与向量的长度相等&#xff1b;如果输入参数y是矩阵时&#xff0c;则按列绘…...

Python配置镜像源

Python3安装pika的准备 Windows下配置镜像源可以按照如下操作。 1.winR执行%APPDATA% %APPDATA%后&#xff0c;创建pip文件夹&#xff0c;并创建pip.ini配置文件 查看此目录下是否有pip目录&#xff0c;如果没有则需要创建&#xff0c;并在pip目录下以文本方式添加pip.ini文件…...

Linux防火墙Centos6的常用命令iptables

文章目录 一、iptables基础知识二、作者玩玩的配置文件三、iptables中常用的参数以及作用-j参数的动作类型 四、安装iptables五、iptables启动命令六、iptables命令结构命令例子默认执行方式执行iptables命令和写入配置文件两种方式的对比 相对常用的命令参考文档 一、iptables…...

python中的贪心算法-求顾客的最小的等待时间

一. 设有n个顾客同时等待一项服务。顾客i需要的服务时间为ti(1<i<n)。如何安排n个顾客的服务次序才能使顾客总的等待时间达到最小? nint(input(请输入顾客的位数: ))times[] for i in range(n):timeint(input(f请输入顾客{i1}的服务时间: ))times.append(time) times.so…...

【JAVA springframework.http】如何发送HTTP请求

Springboot之restTemplate https://blog.csdn.net/weixin_43702146/article/details/116567707 public Result doHandlePostJson(String restUri, String jsonData)throws Exception {Result result null;try {// logger记录log.info("doHandlePostJson request restUr…...

字符串反转(Python)

1. 整体流程 为了实现递归反转n个字符串的功能&#xff0c;我们可以按照以下步骤进行操作&#xff1a; 步骤动作1定义递归函数2判断递归结束条件3处理递归函数的基本情况4调用递归函数&#xff0c;递归处理子问题5返回递归结果 我将详细解释每一步的具体操作&#xff0c;并提…...

驱动开发day4

通过字符设备驱动的分步实现编写LED驱动&#xff0c;另外实现设备文件和驱动的绑定 head.h #ifndef __HEAD_H__ #define __HEAD_H__ typedef struct {unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR; }…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...

MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释

以Module Federation 插件详为例&#xff0c;Webpack.config.js它可能的配置和含义如下&#xff1a; 前言 Module Federation 的Webpack.config.js核心配置包括&#xff1a; name filename&#xff08;定义应用标识&#xff09; remotes&#xff08;引用远程模块&#xff0…...

Appium下载安装配置保姆教程(图文详解)

目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...

RushDB开源程序 是现代应用程序和 AI 的即时数据库。建立在 Neo4j 之上

一、软件介绍 文末提供程序和源码下载 RushDB 改变了您处理图形数据的方式 — 不需要 Schema&#xff0c;不需要复杂的查询&#xff0c;只需推送数据即可。 二、Key Features ✨ 主要特点 Instant Setup: Be productive in seconds, not days 即时设置 &#xff1a;在几秒钟…...