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

[C++] 轻熟类和对象

Kevin的技术博客.png

类的定义

格式规范

  • class为定义类的关键字,后有类名,类的主体存于{}中;
  • 类定义结束时后面的分号不能省略;
  • 类体的内容成为类的成员,类中的变量成为成员变量,函数成为方法或成员函数;
  • C++兼容C语言的struct用法,同时将struct升级成了类的用法(更推荐类)
  • 在类定义中直接定义一个成员函数(即在类声明的花括号{}内直接给出函数体),编译器会默认将这个成员函数视为inline。这样做的好处是,如果成员函数非常简单,编译器可以优化代码,通过内联展开来提高程序的执行效率。

举例代码:

class Stack
{
public:// 成员函数void Init(int n = 4){array = (int*)malloc(sizeof(int) * n);if (nullptr == array){perror("malloc申请空间失败");return;}capacity = n;top = 0;private:// 成员变量int* array;size_t capacity;size_t top;
}; // 分号不能省略

访问限定符

封装的概念

封装是OOP的一个基本原则,它指的是将数据(属性)和操作这些数据的代码(方法)组合在一起,形成一个单元。封装的主要目的是隐藏内部实现的细节,只暴露出一个可以被外界访问和操作的接口。

  1. 数据封装:类定义了属性(也称为成员变量或字段),这些属性代表了对象的状态。封装确保了这些属性只能通过类提供的方法来访问和修改,从而保护数据不被外部代码直接访问,避免数据被不当操作。
  2. 方法封装:类还定义了方法(也称为成员函数或行为),这些方法定义了可以对对象执行的操作。封装确保了对象的行为是通过这些方法来实现的,而不是直接操作对象的内部状态。

访问限定符

image.png

  1. 隐藏实现细节:通过使用private访问限定符,类的实现细节被隐藏起来,外部代码不能直接访问或修改对象的内部状态,只能通过public方法来操作。
  2. 提供接口:public方法提供了一个接口,允许外部代码以受控的方式与对象交互。这些方法可以包含对private成员的访问和修改,但这些操作的细节对外部是不可见的。
  3. 继承和多态性:protected访问限定符允许子类访问和修改父类的某些成员,这在实现继承和多态性时非常有用。子类可以扩展或修改父类的行为,同时保持对外部代码的封装。
  4. 维护数据完整性:通过限制对属性的直接访问,封装确保了数据的完整性和一致性。
  5. 促进模块化:封装使得代码更加模块化,每个类负责管理自己的数据和行为,减少了不同模块之间的耦合。(高内聚、低耦合)

类域

类会定义一个新的作用域,类的所有成员都在类的作用域中,在类外定义成员时需要用::作用域操作符指明成员属于哪个类域。

在类外定义成员函数:

#include<iostream>using namespace std;class Stack
{public:// 成员函数void Init(int n = 4);
private:// 成员变量int* array;size_t capacity;size_t top;};// 声明和定义分离,需要指定类域void Stack::Init(int n){array = (int*)malloc(sizeof(int) * n);if (nullptr == array){perror("malloc申请空间失败");return;}capacity = n;top = 0;}

实例化

概念

类是一个蓝图或模板,它定义了一组属性(成员变量)和方法(成员函数),这些属性和方法共同描述了一类事物的特征和行为。而通过创建对象就可以将对象进行实例化,这一一种一对多的关系,一个类可以创造多个对象,每一个类都是一个个体实例,并不冲突。

// 如何实例化对象// 定义一个日期类
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和d2Date d1;Date d2;d1.Init(2024, 3, 31);d1.Print();d2.Init(2024, 7, 5);d2.Print();return 0;
}

对象⼤⼩

对象中只存储成员变量,每个成员函数在对象调用的时候用的都是同一个指针来访问。对于对象的大小,要符合内存对齐的规则,关于内存对齐的详细运用理解可以点击蓝字阅读我的另一篇博客,具体的规则大概如下:
• 第⼀个成员在与结构体偏移量为0的地址处。
• 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。
• 注意:对⻬数 = 编译器默认的⼀个对⻬数 与 该成员⼤⼩的较⼩值。
• VS中默认的对⻬数为8
• 结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍。
• 如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩ 就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍。
•不要忘记内存对齐的目的:为了减少CPU访问内存次数,提高效率。

this指针

编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this指针。⽐如Date类的Init的真实原型为, void Init(Date* const this, int year, int month, int day),但是C++规定不能在实参和形参位置上写this指针,但是可以在函数体内显式使用this指针

  • 类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值, this->_year = year;。所以通过this指针可以对于一个对象的维护更加便捷。
// 显式使用this指针
void Init(int year, int month, int day)
{_year = year;this->_month = month;this->_day = day;
}

存储位置

关于this指针在内存上的存储位置:当成员函数被调用时,this 指针通常存储在调用栈上。调用栈是用于存储函数调用时的局部变量和状态信息的内存区域。


image.png

相关文章:

  • 内网信息收集:手动、脚本和工具查IP、端口
  • 5-3.损失函数
  • Docker 日志丢失 - 解决方案
  • Python基于you-get下载网页上的视频
  • scipy库中,不同应用滤波函数的区别,以及FIR滤波器和IIR滤波器的区别
  • Perl 数据类型
  • 【RHCE】转发服务器实验
  • vue3项目安装和使用element-plus
  • 推荐算法有哪些?——协同过滤、内容推荐、DNN、FM、DeepFM
  • Android使用http加载自建服务器静态网页
  • android gradle开发基础
  • vue项目中常见的一些preset及其关系
  • 【Spring成神之路】老兄,来一杯Spring AOP源码吗?
  • Java多线程面试题
  • IPython的交互式命令行:交互式命令行界面
  • 【React系列】如何构建React应用程序
  • Apache的基本使用
  • Docker容器管理
  • java 多线程基础, 我觉得还是有必要看看的
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • Lsb图片隐写
  • Map集合、散列表、红黑树介绍
  • mysql中InnoDB引擎中页的概念
  • ng6--错误信息小结(持续更新)
  • ReactNative开发常用的三方模块
  • Redis 懒删除(lazy free)简史
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 近期前端发展计划
  • 利用jquery编写加法运算验证码
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 怎么把视频里的音乐提取出来
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • $jQuery 重写Alert样式方法
  • (2.2w字)前端单元测试之Jest详解篇
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (八)c52学习之旅-中断实验
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (每日一问)操作系统:常见的 Linux 指令详解
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • .bashrc在哪里,alias妙用
  • .NET C# 使用GDAL读取FileGDB要素类
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .NET Framework杂记
  • .net 调用php,php 调用.net com组件 --
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .Net 中Partitioner static与dynamic的性能对比
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • @Autowired 和 @Resource 区别的补充说明与示例
  • @Transactional事务注解内含乾坤?