当前位置: 首页 > 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…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...