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

【C++从小白到大牛】类和对象

目录

 一、面向过程和面向对象初步认识

二、类的引入

三、类的定义

类的成员函数两种定义方式:

1. 声明和定义全部放在类体中

2. 类声明放在.h文件中,成员函数定义放在.cpp文件中

成员变量命名规则的建议:

四、类的访问限定符

【访问限定符说明】

问题:C++中struct和class的区别是什么?

五、类的实例化

六、如何计算类对象的大小

结论:

七、this指针

面试题:

1、this指针存在哪里,是存在对象里面的吗

八、static成员

静态成员和静态成员函数的特性

九、对于隐式类型转换的那些事儿

第一类是内置类型中的隐式类型转换,主要就是整形和浮点型之间的转换。

第二类就是内置类型隐式类型转换为自定义类型

 一、面向过程和面向对象初步认识

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

C++是基于面向对象的,关注的是对象,将一件事拆分成不同的对象,靠对象之间的交互完成。

二、类的引入

C++中的类相比于C语言的结构体有两点升级。

1、类名就是类型,Stack就是类型,不需要加struct(在C语言中类型还要加上struct)

2、 C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。

比如:之前在数据结构初阶中,用C语言方式实现的栈,结构体中只能定义变量;现在以C++方式实现,会发现struct中也可以定义函数。

typedef int DataType;
struct Stack
{void Init(size_t capacity){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (nullptr == _array){perror("malloc申请空间失败");return;}_capacity = capacity;_size = 0;}void Push(const DataType& data){// 扩容_array[_size] = data;++_size;}DataType Top(){return _array[_size - 1];}void Destroy(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}DataType* _array;size_t _capacity;size_t _size;
};
int main()
{Stack s;s.Init(10);s.Push(1);s.Push(2);s.Push(3);cout << s.Top() << endl;s.Destroy();return 0;
}

上面结构体的定义,在C++中更喜欢用class来代替。

通过上面的代码,我们发现C++中类的作用是非常显著的!比C语言简便许多!

可以直接将函数定义在类的内部,如果一个工程中定义多个数据结构,我们只需要将类进行实例化,不需要担心不同数据结构的函数回命名冲突。

三、类的定义

class className
{
// 类体:由成员函数和成员变量组成
};  // 一定要注意后面的分号

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

类中的变量称为类的属性或成员变量;

类中的函数称为类的方法或者成员函数。

类的成员函数两种定义方式:

1. 声明和定义全部放在类体中

需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。

为什么是可能将其看成内联函数呢?

因为编译器有自己的一套保护系统,不信任程序员,前文讲过内联函数如果代码量过于大(一般超过10行就算大),就自动不认为他是一个内联函数,就算定义在类里面也不行。

2. 类声明放在.h文件中,成员函数定义放在.cpp文件中

注意:成员函数名前需要加类名::

标准正确定义的方法:

长的函数声明和定义分离;短小的函数可以直接在类里面定义

成员变量命名规则的建议:

// 我们看看这个函数,是不是很僵硬?
class Date
{
public:void Init(int year){// 这里的year到底是成员变量,还是函数形参?year = year;}
private:int year;
};
// 所以一般都建议这样
class Date
{
public:void Init(int year){_year = year;}
private:int _year;
};
// 或者这样
class Date
{
public:void Init(int year){mYear = year;}
private:int mYear;
};
// 其他方式也可以的,主要看公司要求。一般都是加个前缀或者后缀标识区分就行。

四、类的访问限定符

访问限定符
C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用

【访问限定符说明】

  1. public修饰的成员在类外可以直接被访问
  2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  3. 如果后面没有访问限定符,作用域就到 } 即类结束。
  4. class的默认访问权限为private,struct为public(因为struct要兼容C)

问题:C++中struct和class的区别是什么?

解答:

C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。

五、类的实例化

用类类型创建对象的过程,称为类的实例化(类和对象的关系)

一个类可以实例化出多个对象,实例化出的对象才占用实际的物理空间,存储类成员变量
Person类是没有空间的,只有Person类实例化出的对象才有具体的年龄。

int main()
{Person._age = 100;   // 编译失败:error C2059: 语法错误:“.”return 0;
}

类的实例化正确使用方法:

六、如何计算类对象的大小

问题:类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类的大小?

如果对象中包含类的各个成员?

每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一个类创建多个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间。

所以我们采取下面的存储方式

结论:

一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐
注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。

计算类的大小时,类的成员函数不包括在内,为何?

因为不同的对象使用的都是同一个函数(比如初始化函数等),但不同的对象使用的都是不同的成员变量。多次调用相同函数而浪费了空间,因此我们可以把函数存储在公共区域,不用计入类的大小。

七、this指针

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()
{Date d1, d2;d1.Init(2022,1,11);d2.Init(2022, 1, 12);d1.Print();d2.Print();return 0;
}

对于上述类,有这样的一个问题:
Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?


C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

不能显示写出this相关实参和形参,但是可以在类里面显示使用

注意成员函数里面比别的函数默认多一个参数,本来没有参数的会有1个参数,本来有一个参数,就会有2个参数,那个多出来的参数就是this传的参数

面试题:

1、this指针存在哪里,是存在对象里面的吗

首先明确this指针不可能存在对象里面,我们上文讲过计算对象的大小时,是没有计算this指针大小的,所以反向思维this指针是不存在对象里。

this指针实际上是一个形参,是存放在栈帧里面的,VS编译器下,是存放在ecx寄存器里面。

2、比较下面两种代码的区别

注意对空指针解引用是运行错误,编译时不会报错。

上面代码执行结果为什么是正常运行?

我们来分析一下。

首先p是一个指针,并且是空指针,注意当指针定义的对象时,就需要用->来访问成员变量。

那p是空指针了怎么再访问Print函数呢?

我们不要忘了成员函数的地址不在对象中,只有成员变量才存放在对象中!

所以p里面根本就没有函数,也就不存在指针解引用了。

这里的p作用表示在编译时检查Print是不是在类里面。


再对比看看下面的代码:

因为this指针就是空指针,而解引用空指针去访问成员变量肯定是报错的!

八、static成员

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。

静态成员变量一定要在类外进行初始化!类里面声明,类外面定义

原因:

类里面初始化的缺省值,本质上是给初始化列表的,但是静态成员变量不要走初始化列表,因为初始化列表要定义一个对象里的成员。但是静态成员变量不是属于某个对象的,是属于整个类的

面试题:实现一个类,计算程序中创建出了多少个类对象。

class A
{
public:
A() { ++_scount; }
A(const A& t) { ++_scount; }
~A() { --_scount; }
static int GetACount() { return _scount; }
private:
static int _scount;
};int A::_scount = 0;//静态成员变量需要在类外初始化void TestA()
{
cout << A::GetACount() << endl;
A a1, a2;
A a3(a1);
cout << A::GetACount() << endl;
}

静态成员和静态成员函数的特性

1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制

总结一下:

静态成员函数和静态成员变量,本质就是受限制的全局变量和全局函数,专属这个类,受类域和访问限定符的限制。

问题:

1、静态成员函数能调用非静态成员函数吗?

答:不可以,因为静态成员函数没有this指针,同样也不能访问非静态成员变量

2、非静态成员函数能调用静态成员函数吗?

答:可以

九、对于隐式类型转换的那些事儿

首先分为两大类:

第一类是内置类型中的隐式类型转换,主要就是整形和浮点型之间的转换。

注意这里引用需要加上const,但赋值不需要加。因为隐式类型转换中间会产生临时变量,而临时变量具有常性!这里的引用是将临时变量引用给了r,具有常性,所以要加上const;而赋值是将临时变量直接赋值给d,不需要加上const!

第二类就是内置类型隐式类型转换为自定义类型

注意这里的   A aa3 = 3   就是将内置类型隐式转换为了自定义类型,原理是自定义类型中包含了int单参数构造函数(支持传一个参数或者多参数带缺省也可以)的支持,如果不想让转换发生,构造函数加explicit关键字。

注意这里的引用需要加上const原理与上面一样,因为隐式类型转换会生成临时变量,而临时变量会具有常性。

如果是多参数,可以选择用大括号  { }  进行表示!

相关文章:

【C++从小白到大牛】类和对象

目录 一、面向过程和面向对象初步认识 二、类的引入 三、类的定义 类的成员函数两种定义方式&#xff1a; 1. 声明和定义全部放在类体中 2. 类声明放在.h文件中&#xff0c;成员函数定义放在.cpp文件中 成员变量命名规则的建议&#xff1a; 四、类的访问限定符 【访问限…...

Kafka 为什么这么快的七大秘诀,涨知识了

我们都知道 Kafka 是基于磁盘进行存储的&#xff0c;但 Kafka 官方又称其具有高性能、高吞吐、低延时的特点&#xff0c;其吞吐量动辄几十上百万。 在座的靓仔和靓女们是不是有点困惑了&#xff0c;一般认为在磁盘上读写数据是会降低性能的&#xff0c;因为寻址会比较消耗时间。…...

一文解决3D车道线检测:最新单目3D车道线检测综述

前言 场景理解是自动驾驶中极具挑战的任务&#xff0c;尤其是车道检测。车道是道路分割的关键&#xff0c;对车辆安全高效行驶至关重要。车道检测技术能自动识别道路标记&#xff0c;对自动驾驶车辆至关重要&#xff0c;缺乏这项技术可能导致交通问题和事故。车道检测面临多种…...

稳中向好,今年新招6000人

团子校招 近日&#xff0c;美团宣布开启面向 2025 届的校园招聘&#xff0c;招聘规模达 6000 人。 虽然相比京东&#xff08;宣布招聘 16000 人&#xff09;稍有逊色&#xff0c;但 6000 这个校招规模可一点不少。 要知道&#xff0c;京东是重自营的传统电商&#xff0c;16000 …...

使用kettle开源工具进行跨库数据同步

数据库同步可以用&#xff1a; 1、Navicat 2、Kettle 3、自己写代码 调用码神工具跨库数据同步 -连接 4、其它 实现 这里使用Kettle来同步&#xff0c;主要是开源的&#xff0c;通过配置就可以实现了 Kettle的图形化界面&#xff08;Spoon&#xff09;安装参考方法 ht…...

Golang | Leetcode Golang题解之第307题区域和检索-数组可修改

题目&#xff1a; 题解&#xff1a; type NumArray struct {nums, tree []int }func Constructor(nums []int) NumArray {tree : make([]int, len(nums)1)na : NumArray{nums, tree}for i, num : range nums {na.add(i1, num)}return na }func (na *NumArray) add(index, val …...

Golang | Leetcode Golang题解之第301题删除无效的括号

题目&#xff1a; 题解&#xff1a; func checkValid(str string, lmask, rmask int, left, right []int) bool {cnt : 0pos1, pos2 : 0, 0for i : range str {if pos1 < len(left) && i left[pos1] {if lmask>>pos1&1 0 {cnt}pos1} else if pos2 <…...

【Story】《程序员面试的“八股文”辩论:技术基础与实际能力的博弈》

目录 程序员面试中的“八股文”&#xff1a;助力还是阻力&#xff1f;1. “八股文”的背景与定义1.1 “八股文”的起源1.2 “八股文”的常见类型 2. “八股文”的作用分析2.1 理论基础的评价2.1.1 助力2.1.2 阻力 3. 实际工作能力的考察3.1 助力3.2 阻力 4. 面试中的背题能力4.…...

初步了解泛型

目录 泛型的引入 泛型 泛型 泛型类 泛型的上界 泛型的引入 之前学习的数组里面是存放着整型或者自字符串中一种的数组&#xff0c;如果想要在一个数组里面放多种类型数据&#xff0c;我们该怎么去做呢&#xff1f;Object类或许是一个好的解决方法&#xff0c;因为Object类…...

【C#】.net core 6.0 webapi 使用core版本的NPOI的Excel读取数据以及保存数据

欢迎来到《小5讲堂》 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景读取并保存NPOI信息NPOI 插件介绍基本功能示例代码写入 Excel 文件…...

C++推荐的oj网站

洛谷 信息学奥赛一本通 C语言网 codeforces 杭电oj...

springmvc处理http请求的底层逻辑

http-nio-8088-Poller线程中在org.apache.tomcat.util.net.NioEndpoint.Poller#run这个函数里循环检测selector&#xff0c;若发现有SocketEvent.OPEN_READ事件则会将SelectionKey.attachment中的内容作为入参包装成runable&#xff0c;然后由org.apache.tomcat.util.threads.T…...

干货满满,从零到一:编程小白如何在大学成为编程大神?

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…...

前端-如何通过docker打包Vue服务成镜像并在本地运行(本地可以通过http://localhost:8080/访问前端服务)

1、下载安装docker&#xff0c;最好在vs code里安装docker的插件。 下载链接&#xff1a;https://www.docker.com/products/docker-desktop &#x1f389; Docker 简介和安装 - Docker 快速入门 - 易文档 (easydoc.net) 2、准备配置文件-dockerfile文件和nginx.conf文件 do…...

零基础学习【Mybatis】这一篇就够了

Mybatis 查询resultType使用resultMap使用单条件查询多条件查询模糊查询返回主键 动态SQLifchoosesetforeachsql片段 配置文件注解增删改查结果映射 查询 resultType使用 当数据库返回的结果集中的字段和实体类中的属性名一一对应时, resultType可以自动将结果封装到实体中 r…...

Shell入门(保姆级教学)

Shell是一种命令行解释器&#xff0c;也是一种脚本语言&#xff0c;广泛应用于Unix和类Unix系统中&#xff0c;例如Linux。它是用户与操作系统内核交互的桥梁&#xff0c;通过Shell可以执行系统命令、管理文件系统、处理文本数据等。本文将带你入门Shell编程&#xff0c;涵盖基…...

【JDK11和JDK8并行与切换】

一、JDK11安装 1、下载jdk11&#xff0c;点击.exe安装在&#xff1a;C:\Program Files\Java\jdk-11\ 2、配置JAVA_HOME 变量名为JAVA_HOME 变量值为jdk安装路径 3、配置PATH 找到系统变量里的PATH 双击或者单击后点击编辑 点击右上角的新建 新建两条 %JAVA_HOME%\bin …...

vue大数据量列表渲染性能优化:虚拟滚动原理

前面咱完成了自定义JuanTree组件各种功能的实现。在数据量很大的情况下&#xff0c;我们讲了两种实现方式来提高渲染性能&#xff1a;前端分页和节点数据懒加载。 前端分页小节&#xff1a;Vue3扁平化Tree组件的前端分页实现 节点数据懒加载小节&#xff1a;Element Tree Plu…...

昇思25天学习打卡营第1天|快速入门

目录 昇思MindSpore介绍MindSpore的API来快速实现一个简单的深度学习模型通过资料更深入的了解昇思MindSpore 昇思MindSpore介绍 今天有幸学习了昇思MindSpore&#xff0c;让我们来简单的了解一下它 昇思MindSpore是一个全场景深度学习框架&#xff0c;旨在实现易开发、高效执行…...

LinkedList 实现 LRU 缓存

LRU&#xff08;Least Recently Used&#xff0c;最近最少使用&#xff09;缓存是一种缓存淘汰策略&#xff0c;用于在缓存满时淘汰最久未使用的元素。 关键&#xff1a; 缓存选什么结构&#xff1f; 怎么实现访问顺序&#xff1f; import java.util.*;public class LRUCac…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...