【C++】类与对象 第一篇(class,this)
目录
什么是类?
类的引入
class
类的两种定义方式:
声明与定义分离
类的访问限定符号
访问限定符编辑
C++中struct和class的区别是什么?
封装
类的作用域
类的实例化
类对象模型
如何计算类对象的大小
this指针
C语言和C++实现Stack的对比
C语言实现
C++实现
什么是类?
在C++中,类(Class)是一种用户自定义的数据类型,用于封装数据和方法。它是面向对象程序设计的基本概念之一,通过将相关的数据和方法捆绑在一起,可以更加清晰和灵活地组织代码。
类可以看作是一个模板或者蓝图,用于创建对象(Object)。类定义了对象的属性(成员变量)和行为(成员函数)。成员变量是类的数据成员,用于存储对象的状态;成员函数是类的成员操作,用于操作和访问对象的状态。
通过使用类,能够将数据和操作封装在一起,实现了数据的隐藏和封装,提供了更好的代码重用性和可维护性。同时,类还支持继承机制,允许创建一个类继承另一个类的属性和方法,进一步提高了代码的灵活性和可扩展性。 c语言与c++的区别:
-
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
-
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
C语言更像是人们用双手进行洗衣服,不仅需要自己准备洗衣服相关的物品 而C++则是只需人们讲衣服放进洗衣机,洗衣机讲帮你完成这一过程,并且无需关心是如何洗好的
类的引入
C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。比如: 之前在数据结构初阶中,用C语言方式实现的栈,结构体中只能定义变量;现在以C++方式实现, 会发现struct中也可以定义函数
//c++兼容C结构体用法typedef struct ListNode{int val;struct ListNode* next;}LTN;//C的结构体类型是 struct ListNode//C++把结构体升级成了类//类是一个整体struct Stack{void Init(int n=4)//缺省参数{a=(int*)malloc(sizeof(int)*n);if(nullptr==a){perror("malloc is fail");return;}capacity=n;size=0;}void Push(int x){//...a[size++]=x;}int* a;int size;int capacity;};int main(){Stack st;st.Init();st.Push(1);st.Push(2);st.Push(3);return 0;}
但在C++中一般用class进行类的定义(或C++中更喜欢用class代替)
class
class className{// 类体:由成员函数和成员变量组成 }; // 一定要注意后面的分号
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者 成员函数。
struct Stack{//成员函数void Init(int n=4){a=(int*)malloc(sizeof(int)*n);if(nullptr==a){perror("malloc is fail");return;}capacity=n;size=0;}//成员变量 位置任意 int* a;int size;int capacity;};
类的两种定义方式:
-
声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内 联函数处理
class Person{public:void Show(){//...}public:char* _name;char* _sex;int _age;};
-
声明与定义分离
//Stack.hclass Stack{//成员函数void Init(int n=4);void Push(int x);//成员变量 int* a;int size;int capacity;};//Stack.cpp#include "Stack.h"void Stack::Init(int n){a=(int*)malloc(sizeof(int)*n);if(nullptr==a){perror("malloc is fail");return;}capacity=n;size=0;}void Stack::Push(int x){//...}//注意:缺省值的定义一般是在声明时定义
类的访问限定符号
访问限定符
【访问限定符说明】
1.public修饰的成员在类外可以直接被访问
2.protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4.如果后面没有访问限定符,作用域就到 } 即类结束。
5.class的默认访问权限为private,struct为public(因为struct要兼容C) 注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
class Stack{public://成员函数void Init(int n=4);void Push(int x);private://成员变量 int* a;int size;int capacity;};
注意:成员变量命名时,一般都会在定义变量名字前后➕_ 以防混淆,如:class D{public://成员函数void Init(int year,int month,int day){_year=year;_month=month;_year=year;}private://成员变量 int _year;int _month;int _day;};
C++中struct和class的区别是什么?
C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来 定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类 默认访问权限是private。注意:在继承和模板参数列表位置,struct和class也有区别
封装
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
封装本质上是一种管理,让用户更方便使用类。比如:对于电脑这样一个复杂的设备,提供给用 户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日 常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。
类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
class Person{public:void PrintPersonInfo();private:char _name[20];char _gender[3];int _age;};// 这里需要指定PrintPersonInfo是属于Person这个类域void Person::PrintPersonInfo(){cout << _name << " "<< _gender << " " << _age << endl;}
类的实例化
用类类型创建对象的过程,称为类的实例化
-
类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没 有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个 类,来描述具体学生信息。
类就像谜语一样,对谜底来进行描述,谜底就是谜语的一个实例。
-
一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
Person类是没有空间的,只有Person类实例化出的对象才有具体的年龄。
int main() {Person._age = 100; // 编译失败:error C2059: 语法错误:“.”return 0; }
-
做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设 计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象 才能实际存储数据,占用物理空间
定义时才开空间(类对象的实例化)
//类-设计图纸class Data{public://成员函数void Init(int year,int month,int day){_year=year;_month=month;_year=year;}private://声明int _year;int _month;int _day;};int main(){//类对象实例化 -- 开空间//实例化 -- 用设计图建造房子Data d1;Data d2;return 0;}
错误用法:
类对象模型
如何计算类对象的大小
class Data{public://成员函数void Init(int year,int month,int day){_year=year;_month=month;_year=year;}//声明int _year;int _month;int _day;};int main(){Data d1;Data d2;d1.Init(2077,2,2); d1._year++;cout<<sizeof(d1)<<endl;//12return 0;}
为什么 d1 是12字节?
成员函数就像是公共设施,在计算大小时只需要将属于自己的进行计算即可 每个对象成员变量是不一样的,需要单独存储,每个对象调用成员函数是一样的,放到共享区域(代码段)
此处计算占有大小也存在内存对齐问题(内存对齐问题具体讲解C语言:自定义类型(结构体,枚举,联合)-CSDN博客)
结构体内存对齐规则
第一个成员在与结构体偏移量为0的地址处。
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的对齐数为8
结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
// 类中既有成员变量,又有成员函数 class A1 {public:void f1(){}private:int _a;};// 类中仅有成员函数 class A2 { public:void f2() {}};// 类中什么都没有---空类 class A3{};
sizeof(A1)=4;sizeof(A2)=1;sizeof(A3)=1;这是为什么呢?
sizeof(A2)=1; sizeof(A3)=1; 这1字节仅仅是用来占位的,表示对象存在,被实例化
this指针
这就引入了this,此处this是编译器自动生成的,无需自定义,进行自定义也会报错
当然这样写是正确的,此处写与不写都一样
那this存放在哪里?-- 存放才栈上,应为它是隐含形参
Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢? C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏 的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编 译器自动完成。
// 下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行 class Date{public:void Init(int year,int month,int day){cout << this << endl;this->_year = year;this->_month = month;this->_day = day;}void Print(){cout << this << endl;cout << "Print()" << endl;} private:int _year;int _month;int _day;};int main() {Date* ptr = nullptr;ptr->Print(); //正常运行//ptr->Init(2077,2,2); //运行崩溃return 0;}
ptr->Print(); 正常运行的原因: 调用成员函数要调用成员指针,此时ptr传递给了this,此时this指针本身为空不报错
ptr->Init(2077,2,2); 运行崩溃的原因: 此处调用了this (this->_year = year;)对this进行了解引用
ptr->Print();//正常运行(*ptr).func();//正常运行
正常运行的原因:有没有解引用的行为取决于右边要访问的对象在不在对象里面,而不是有没有用那个符号
C语言和C++实现Stack的对比
C语言实现
typedef int DataType;typedef struct Stack{DataType *array;int capacity;int size;} Stack;void StackInit(Stack *ps){assert(ps);ps->array = (DataType *)malloc(sizeof(DataType) * 3);if (NULL == ps->array){assert(0);return;}ps->capacity = 3;ps->size = 0;}void StackDestroy(Stack *ps){assert(ps);if (ps->array){free(ps->array);ps->array = NULL;ps->capacity = 0;ps->size = 0;}}void CheckCapacity(Stack *ps){if (ps->size == ps->capacity){int newcapacity = ps->capacity * 2;DataType *temp = (DataType *)realloc(ps->array, newcapacity * sizeof(DataType));if (temp == NULL){perror("realloc申请空间失败!!!");return;}ps->array = temp;ps->capacity = newcapacity;}}void StackPush(Stack *ps, DataType data){assert(ps);CheckCapacity(ps);ps->array[ps->size] = data;ps->size++;}int StackEmpty(Stack *ps){assert(ps);return 0 == ps->size;}void StackPop(Stack *ps){if (StackEmpty(ps))return;ps->size--;}DataType StackTop(Stack *ps){assert(!StackEmpty(ps));return ps->array[ps->size - 1];}int StackSize(Stack *ps){assert(ps);return ps->size;}int main(){Stack s;StackInit(&s);StackPush(&s, 1);StackPush(&s, 2);StackPush(&s, 3);StackPush(&s, 4);printf("%d\n", StackTop(&s));printf("%d\n", StackSize(&s));StackPop(&s);StackPop(&s);printf("%d\n", StackTop(&s));printf("%d\n", StackSize(&s));StackDestroy(&s);return 0;}
可以看到,在用C语言实现时,Stack相关操作函数有以下共性: 每个函数的第一个参数都是Stack* 函数中必须要对第一个参数检测,因为该参数可能会为NULL 函数中都是通过Stack*参数操作栈的 调用时必须传递Stack结构体变量的地址
结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据 的方式是分离开的,而且实现上相当复杂一点,涉及到大量指针操作,稍不注意可能就会出错。
C++实现
typedef int DataType;class Stack{public:void Init(){_array = (DataType *)malloc(sizeof(DataType) * 3);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = 3;_size = 0;}void Push(DataType data){CheckCapacity();_array[_size] = data;_size++;}void Pop(){if (Empty())return;_size--;}DataType Top(){return _array[_size - 1];}int Empty(){return 0 == _size;}int Size(){return _size;}void Destroy(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}private:void CheckCapacity(){if (_size == _capacity){int newcapacity = _capacity * 2;DataType *temp = (DataType *)realloc(_array, newcapacity *sizeof(DataType));if (temp == NULL){perror("realloc申请空间失败!!!");return;}_array = temp;_capacity = newcapacity;}}private:DataType *_array;int _capacity;int _size;};int main(){Stack s;s.Init();s.Push(1);s.Push(2);s.Push(3);s.Push(4);printf("%d\n", s.Top());printf("%d\n", s.Size());s.Pop();s.Pop();printf("%d\n", s.Top());printf("%d\n", s.Size());s.Destroy();return 0;}
C++中通过类可以将数据 以及 操作数据的方法进行完美结合,通过访问权限可以控制那些方法在 类外可以被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。 而且每个方法不需要传递Stack的参数了,编译器编译之后该参数会自动还原,即C++中Stack 参数是编译器维护的,C语言中需用用户自己维护
c:
1.数据都是分离的
2.数据访问控制是自由的,不受限制
c++:
1.数据和方法都封装到类里面
2.控制访问方式,给你访问公有,不能访问私有
相关文章:

【C++】类与对象 第一篇(class,this)
目录 什么是类? 类的引入 class 类的两种定义方式: 声明与定义分离 类的访问限定符号 访问限定符编辑 C中struct和class的区别是什么? 封装 类的作用域 类的实例化 类对象模型 如何计算类对象的大小 this指针 C语言和C实现Stack的对比 C语言实现…...

嵌入式软件工程师面试题——2025校招专题(四)
说明: 面试题来源于网络书籍,公司题目以及博主原创或修改(题目大部分来源于各种公司);文中很多题目,或许大家直接编译器写完,1分钟就出结果了。但在这里博主希望每一个题目,大家都要…...

actual combat 21——华为云从零开始项目部署(附nginx转发域名方式)
一、IP地址方式: 后端: 确保项目本地跑通建立并运行华为云流水线 前端: 打包(测试环境)手动上传 nginx: 配置一下即可 华为云: 安全组:暴露后端网关端口安全组:暴…...

@CallSuper注解方法学习
CallSuper注解是什么? CallSuper 是 Android 开发中使用的一个注解,它的主要用途是确保在子类重写父类的方法时,调用 super 方法。这在某些情况下是非常有用的,例如当你希望在重写方法时保留父类的默认行为,或者确保子…...

03_Flutter自定义下拉菜单
03_Flutter自定义下拉菜单 在Flutter的内置api中,可以使用showMenu实现类似下拉菜单的效果,或者使用PopupMenuButton组件,PopupMenuButton内部也是使用了showMenu这个api,但是使用showMenu时,下拉面板的显示已经被约定…...

如何查看多开的逍遥模拟器的adb连接端口号
逍遥模拟器默认端口号为:21503。 不过,使用多开器多开的时候,端口就不一定是21503了。 如何查看? 进入G:\xiaoyao\Microvirt\MEmu\MemuHyperv VMs路径中 每多开一个模拟器,就会多出一个文件夹。 进入你要查找端口号…...

2023年中国道路扫雪车分类、市场规模及发展前景分析[图]
道路扫雪车是一种专门用于清除道路上积雪和冰雪的机动车辆,通常配备有雪铲、扫雪刷、除冰剂喷洒系统等装置,用于在雪季或寒冷气候条件下,对道路进行清扫、除雪、除冰等作业,以确保道路的通行安全。 道路扫雪车行业分类 资料来源&…...

【机器学习】迁移学习(Transfer)详解!
1. 什么是迁移学习 迁移学习(Transfer Learning)是一种机器学习方法,就是把为任务 A 开发的模型作为初始点,重新使用在为任务 B 开发模型的过程中。迁移学习是通过从已学习的相关任务中转移知识来改进学习的新任务,虽然大多数机器学习算法都是…...

软件测试面试题
软件测试面试时一份好简历的重要性 软件的生命周期(prdctrm) 计划阶段(planning)-〉需求分析(requirement)-〉设计阶段(design)-〉编码(coding)->测试&am…...

分治算法解决归并排序问题
分治算法定义:分治算法是一种问题解决方法,它将一个大问题划分为多个相同或相似的子问题,然后递归地解决这些子问题,最后将子问题的解合并得到原问题的解 作用: 排序算法分治算法在排序算法中得到广泛应用。例如&…...

Spring Security漏洞防护—HttpFirewall和 HTTPS
一、HttpFirewall Spring Security有几个领域,你所定义的 pattern 会针对传入的请求进行测试,以决定应该如何处理请求。这发生在 FilterChainProxy 决定请求应该通过哪个过滤链时,以及 FilterSecurityInterceptor 决定哪些安全约束适用于请求…...

Makefile泛谈
Makefile工作原理 1、检查规则中的依赖文件是否存在。 2、若依赖文件不存在,则寻找是否有规则用来生成该依赖文件。 譬如,执行文件会先寻找.o文件是否存在,如果不存在,就会再寻找是否有规则可以生成该依赖文件。如果缺少了main.…...

Python的快捷键
Python Python使用的小快招关于注释关于格式写主函数如何看函数源代码 Python使用的小快招 本文主要记录了写python代码的时候提高效率的一些小妙招 关于注释 选中要注释的代码,然后按下Ctrl /即可对多段代码注释。 关于格式 对于python代码的格式,…...

css为盒子设置滚动条隐藏滚动条
省流:为盒子设置宽高,设置滚动条方向,隐藏滚动条。 首先,要为需要添加滚动条的盒子设置固定的高度和宽度,这样才能让内容超过盒子的边缘。 .box {width: 300px;height: 300px; }然后,给盒子加入overflow属…...

音视频开发常见问题(四):视频花屏和绿屏
摘要 本文介绍了视频视频花屏/绿屏问题的常见原因,如丢失关键帧、metadata的变化、硬件编解码的兼容性问题和颜色格式不一致问题。以及排查方法和解决策略,包括检查视频数据格式、排查自采集/自渲染模块问题、联系第三方音视频SDK技术支持等。最后&…...

设计模式—创建型模式之单例模式
设计模式—创建型模式之单例模式 介绍 单例模式说明:一个单一的类,负责创建自己的对象,同时确保系统中只有单个对象被创建。 单例模式特点: 某个类只能有一个实例;(构造器私有)它必须自行创…...

7.现代卷积神经网络
#pic_center R 1 R_1 R1 R 2 R^2 R2 目录 知识框架No.1 深度卷积神经网络 AlexNet一、AlexNet二、D2L代码注意点三、QA No.2 使用块的网络 VGG一、VGG二、D2L代码注意点三、QA No.3 网络中的网络 NiN一、NIN二、D2L代码注意点三、QA No.4 含并行连结的网络 GoogLeNet / Incep…...

配置Super-VLAN下的DHCP服务器示例
组网需求 如图1所示,某公司拥有两个部门,为了节省IP地址,部门A和部门B规划为同一网段;为了提升业务安全性,将不同部门的用户划分到不同VLAN中。企业管理员为了方便统一管理,希望部门内终端通过DHCP服务器动…...

【开源】基于SpringBoot的城市桥梁道路管理系统的设计和实现
目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询城市桥梁4.2 新增城市桥梁4.3 编辑城市桥梁4.4 删除城市桥梁4.5 查询单个城市桥梁 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的城市桥梁道路管理系统,支持…...

关于根据动态数量的对象的某属性的数组数量呈乘机式增长的数据处理
adta是原始数组,currentIndex默认是零,currentObject初始对象,result处理生成的结果 function generateObjects(data, currentIndex, currentObject, result) {if (currentIndex data.length) {result.push(currentObject);return;}const currentCode data[currentIndex].co…...

数据分析和互联网医院小程序:提高医疗决策的准确性和效率
互联网医院小程序已经在医疗领域取得了显著的进展,为患者和医疗从业者提供了更便捷和高效的医疗服务。随着数据分析技术的快速发展,互联网医院小程序能够利用大数据来提高医疗决策的准确性和效率。本文将探讨数据分析在互联网医院小程序中的应用…...

asp.net学生考试报名管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
一、源码特点 asp.net学生考试报名管理系统是一套完善的web设计管理系统系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使 用c#语言开发 应用技术:asp…...

Python之前端的学习
前端学哪些内容 1. HTML # 网页的骨架、只是负责显示一些内容,但是显示出来的内容不好看,没样式 2. CSS # 对网页骨架的美化、让网页变得更加的好看而已 3. JavaScript # html、css都是不能动的,静态的,js就是让网页能够动起来…...

Python之numpy数组学习(五)——广播
Python之numpy数组学习(五)——广播 目录 Python之numpy数组学习(五)——广播 本文章向大家介绍Python之numpy数组学习(五)——广播,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。 前言 前面我们…...

k8s-----19、Helm
Helm 1、引入2、概述2.1 重点2.2 V3版本的Helm2.2.1 与之前版本的不同之处2.2.2 V3版本的运行流程 3、安装和配置仓库、一些附带操作3.1 安装3.2 配置仓库3.3 常用命令3.4 添加helm的自动补齐 4、快速部署应用(weave应用)5、 自行创建Chart5.1 Chart目录内容解析5.2 简单安装部…...

怒刷LeetCode的第28天(Java版)
目录 第一题 题目来源 题目内容 解决方法 方法一:动态规划 方法二:迭代 方法三:斐波那契数列公式 第二题 题目来源 题目内容 解决方法 方法一:栈 方法二:路径处理类 方法三:正则表达式 方法…...

Kotlin(八) 数据类、单例
目录 一:创建数据类 二:单例类 一:创建数据类 和Java的不同,kotlin的数据类比较简单,New→Kotlin File/Class,在弹出的对话框中输入“Book”,创建类型选择“Data”。如图: 然后编…...

IAR For ARM 安装教程
电脑环境 安装包下载 1、官网下载 ①搜索 IAR ②切换产品,选择Arm ③选择IAR Embedded Workbench for Arm ④免费试用 2、网盘下载 EWARM-CD-8202-14838.exe(访问密码: 1666) https://url48.ctfile.com/f/33868548-961057458-611638?p1666 软件下载 1、点击安…...

向量数据库Weaviate Cloud 和 Milvus Cloud:性能大比拼
最近,随着检索增强生成系统(RAG)的持续火爆,开发者对于“如何选择一个向量数据库”的疑惑也越来越多。过去几周,我们从性能和特性能力两个方面对 Weaviate Cloud 和 MilvusCloud 进行了详细的对比。在对比过程中,我们使用了开源的性能基准测试套件 VectorDBBench,围绕诸…...

微信小程序控制元素显示隐藏
微信小程序是一种轻量级的应用程序,它可以在微信中运行,具有快速、便捷、易用等特点。在微信小程序中,我们可以通过控制元素的显示和隐藏来实现特定的功能。本文将介绍如何使用微信小程序控制元素的显示和隐藏,以及如何应用这些技…...