【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指针的特性
- this指针的类型:类类型* const
- 只能在“成员函数”的内部使用
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的主要特性: 什么是ThinkPHP: ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,诞生于2006年初,由国内的技术爱好者创建,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和…...

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

通过热敏电阻计算温度(二)---ODrive实现分析
文章目录 通过热敏电阻计算温度(二)---ODrive实现分析测量原理图计算分析计算拟合的多项式系数根据多项式方程计算温度的函数温度计算调用函数 通过热敏电阻计算温度(二)—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改进优化之蒸馏(一)-CSDN博客 上一篇已经基本写出来yolov7/v5蒸馏的整个过程,不过要真的训起来我们还需要进行一些修改。 Model修改 蒸馏需要对teacher和student网络的特征层进行loss计算,因此我们forward时要能够返回需…...
生产与作业管理(POM)的历史
1800年,惠特尼:零件标准化、质量管理。 1881年,泰勒:人员选拔、计划和时程安排、动作研究。管理与劳动分开。 - 使雇员与工作相适应。 - 提供适当的训练。 - 提供正确的工作方法和工具。 - 建立适当的激励机制促使工作得以完成。 …...
交换机基础(二)
一、VLAN 基础知识 虚拟局域网 (Virtual Local Area Network,VLAN) 是一种将局域网设 备从逻辑上划分成一个个网段,从而实现虚拟工作组的数据交换技术。 这一技术主要应用于3层交换机和路由器中,但主流应用还是在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 #传纸条
目录 题目:方格取数 思路: 题目:传纸条 思路: 题目:方格取数 (跑两次) 思路: 如果记录一种方案后再去跑另一个方案,影响因素太多了,所以两个方案要同时开…...

前端TypeScript学习day05-索引签名、映射与类型声明文件
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 索引签名类型 映射类型 索引查询(访问)类型 基本使用 同时查询多个索引的类型…...

Echarts柱状图数据过多设置滚动条效果
未设置前: 设置后: dataZoom: [ { show: true, height:8, bottom:0, startValue: 0, //起始值 endValue: 5, //结束值 showDetail: fals…...

64 最长公共子序列
最长公共子序列 题解1 DP 给定两个字符串 text1 和 text2,返回这两个字符串的 最长公共子序列的长度。如果不存在 公共子序列,返回 0 。 一个字符串的子序列是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些…...
matlab常用函数
绘图函数 一、plot():二维图形绘制 1、plot(y): 对于只含一个输入参数的plot函数,如果输入参数y为向量,则以该参数为纵坐标,横坐标从1开始至与向量的长度相等;如果输入参数y是矩阵时,则按列绘…...
Python配置镜像源
Python3安装pika的准备 Windows下配置镜像源可以按照如下操作。 1.winR执行%APPDATA% %APPDATA%后,创建pip文件夹,并创建pip.ini配置文件 查看此目录下是否有pip目录,如果没有则需要创建,并在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个字符串的功能,我们可以按照以下步骤进行操作: 步骤动作1定义递归函数2判断递归结束条件3处理递归函数的基本情况4调用递归函数,递归处理子问题5返回递归结果 我将详细解释每一步的具体操作,并提…...

驱动开发day4
通过字符设备驱动的分步实现编写LED驱动,另外实现设备文件和驱动的绑定 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; }…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...