在这里插入图片描述

在这里插入图片描述
🎁个人主页:工藤新一¹

🔍系列专栏:C++面向对象(类和对象篇)

🌟心中的天空之城,终会照亮我前方的路

🎉欢迎大家点赞👍评论📝收藏⭐文章


文章目录

    • @[toc]
  • C++类和对象(上)
    • 一、类的定义
      • 1.1类定义格式
      • 1.2兼容结构体
    • 二、实例化
      • 2.1实例化概念
      • 2.2对象大小
      • 2.3内存对齐
    • 三、this指针
      • 3.1常量指针与指针常量
      • 3.2面试真题
      • 3.3浅识寄存器 esp/ebp
    • 四、C++与C语言实现Stack对比

C++类和对象(上)

一、类的定义

1.1类定义格式

  • class 为定义类的关键字,以栈为例:Stack 为类的名字,{} 中为类的主体,注意类定义结束时后⾯分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数

  • 为了区分成员变量,⼀般习惯上成员变量会加⼀个特殊标识,如成员变量前⾯或者后⾯加 _ 或者 m 开头,注意 C++ 中这个并不是强制的,只是⼀些惯例,具体看公司的要求

  • 定义在类中的成员函数默认为 inline(内联)

#include<iostream>
using namespace std;
#include<cassert>typedef int STDataType;
class Stack
{
public://成员函数//1、对栈初始化void StackInit(int n = 4){array = (STDataType*)malloc(sizeof(STDataType) * n);if (array == nullptr){perror("malloc fail!");exit(1);}capacity = 4;top = 0;}//2、入栈操作void StackPush(STDataType x){//增容操作if (top == capacity){int newCapacity = capacity == 0 ? 4 : 2 * capacity;STDataRtpe* temp = (STDataType*)realloc(array, newCapacity * sizeof(STDataType));if (temp == nullptr){perror("realloc fail!");exit(1);}array = temp;capacity = newCapacity;}array[top++] = x;}//3、检擦栈顶元素STDataRtpe StackTop(){assert(!StackEmpty());return array[top - 1];}//4、判空操作bool StackEmpty(){return top == 0;}//5、出栈操作void StackPop(){assert(!StackEmpty());/*断言:条件为ture,程序继续执行条件为false,程序停止运行*/top--;}//6、销毁栈void StackDestroy(){if(array)free(array);array = nullptr;top = capacity = 0;}private://成员变量(多个变量的符合)STDataType* array;size_t capacity;size_t top;
};int main()
{Stack st;st.StackInit();return 0;
}

数据结构 ** 中的栈数据写在 结构体中 ,栈操作实现方法在 结构体外,而在类中将数据(成员变量)与实现方法(成员函数)统一写在类内**


1.2兼容结构体

  • C++struct 也可以定义类,C++ 兼容C中 struct 的⽤法,同时 struct 升级成了类,明显的变化是 struct 中可以定义函数,⼀般情况下我们还是推荐⽤ class 定义类
  • C++ 中,struct 的结构体成员默认持有公共权限 public,而 class 的成员对象默认持有私有权限 private

以链表为例:

/*C++ 将 struct 升级为了类1、结构体类中可以定义函数2、struct 名称就可以代表数据类型
*///C++兼容 C 中 struct 的用法
typedef int LTDataType;typedef struct ListNodeC
{LTDataType val;struct ListNodeC* next;//不可以直接在结构体中 ListNodeC* next;}LTNode;//不需要 typedef 修饰,结构体名 ListNodeCPP 就是数据类型
struct ListNodeCPP
{//不仅可以定义变量,也可定义函数void LTInit(LTDataType x){val = x;next = nullptr;}private:LTDataType val;ListNodeCPP* next;
};int main()
{LTNode* node1 = NULL;struct ListNodeC* node2 = NULL;ListNodeCPP* node = nullptr;node->LTInit(1);return 0;
}

本质上:

  • 结构体是数据的集合
  • 类是数据和方法的集合

二、实例化

2.1实例化概念

  • ⽤类类型在物理内存中创建对象的过程,称为类实例化出对象

  • 类是对象进行的⼀种抽象描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只 是声明,没有分配空间,⽤类实例化出对象时,才会分配空间

  • ⼀个类可以实例化出多个对象,实例化出的对象 占⽤实际的物理空间,存储类成员变量。打个⽐ ⽅:类实例化出对象就像现实中使⽤建筑设计图建造出房⼦,类就像是设计图,设计图规划了有多 少个房间,房间⼤⼩功能等,但是并没有实体的建筑存在,也不能住⼈,⽤设计图修建出房⼦,房 ⼦才能住⼈。同样类就像设计图⼀样,不能存储数据,实例化出的对象分配物理内存存储数据

在这里插入图片描述


class Date
{
public:void Init(int year, int month, int day){this->year = year;this->month = month;this->day = day;}private://成员变量是类中的声明(没有开辟任何空间)int year;int month;int day;
};
int main()
{//通过类所实例化出的对象为成员变量开辟空间Date d1, d2;return 0;
}

2.2对象大小

  • 实例对象中,只存储成员变量地址,不存储成员函数地址

​ 分析⼀下类对象中哪些成员呢?类实例化出的每个对象,都有独⽴的数据空间,所以对象中肯定包含 成员变量,那么成员函数是否包含呢?

​ ⾸先 函数被编译后是⼀段指令,在实例对象中没办法存储,这些指令 存储在⼀个单独的区域(代码段),那么实例对象中⾮要存储的话,只能通过 成员函数的指针

​ 再分析⼀下,实例对象中是否有存储指针的必要呢,Date 实例化 d1d2两 个对象,d1d2 都有各⾃独⽴的成员变量 year/_month/_day 存储各⾃的数据,但是 d1d2 的成员函数 Init/Print 指针却是⼀样的,存储在对象中就浪费了。

class Date
{
public:void Init(int year, int month, int day){this->year = year;this->month = month;this->day = day;}private://成员变量是类中的声明(没有开辟任何空间)int year;int month;int day;
};
int main()
{//通过类所实例化出的对象为成员变量开辟空间Date d1, d2;cout << sizeof(Date) << endl;cout << sizeof(d1) << endl;return 0;
}

在这里插入图片描述

汇编角度:函数调用,被定义结束后是一串指令,这串指令会存储到一个单独的区域(常量区,在操作系统的角度上:也称代码段)


在这里插入图片描述


​ 成员变量需要独立的空间存放各种来自外界传入的值

C++//通过不同实例对象调用的 year 需要不同空间存储独立的值(本质:存储地址不同)d1.year++;d2.year++;//成员函数 Print,所有对象共享同一份函数代码,而非单独存储在某一个对象上d1.Print();d2.Print();

​ 如果⽤ Date 实例化100个对象,那么 成员函数指针 就重复存储100次,太浪费了。这⾥需要再额外哆嗦⼀下,其实 函数指针 是不需要存储的,函数指针是⼀个地址,调⽤函数被编译成汇编指 令[call 地址],其实编译器在编译链接时,就要找到函数的地址,不是在运⾏时找, 只有动态多态是在运⾏时找,就需要存储函数地址,这个我们以后会讲解

  • 函数在本文件中有定义 - 编译阶段确定函数地址
  • 函数定义在外文件 - 链接阶段确定函数

在这里插入图片描述


上面我们分析了 实例对象只存储成员变量C++ 规定类实例化的对象也要符合 **内存对齐 **的规则


2.3内存对齐

设计思路:以空间换时间,每个对象从对齐数的位置开始存放

  • 第⼀个成员在与结构体偏移量为 0 的地址处

  • 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处

  • 注意:对⻬数=编译器默认的⼀个对⻬数与该成员⼤⼩的较⼩值

  • VS中默认的对⻬数为 8

  • 结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍

  • 如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩ 就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍


class A
{
public:void Print(){cout << _ch << endl;}
private:char _ch;int _i;
};
class B
{
public:void Print(){//...}
};
class C
{ };
int main()
{cout << sizeof(A) << endl;//8cout << sizeof(B) << endl;//1cout << sizeof(C) << endl;//1return 0;
}
  • 上⾯的程序运⾏后,我们看到没有成员变量的B和C类对象的⼤⼩是 1,为什么没有成员变量还要给1个 字节呢?因为如果⼀个字节都不给,怎么表⽰对象存在过呢!所以这⾥给1字节,纯粹是为了 占位标识 对象存在

面试经典问题:为什么需要内存对齐?

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


三、this指针

  • Date 类中有 InitPrint 两个成员函数,函数体中没有关于不同对象的区分,那当 d1 调⽤ InitPrint 函数时,该函数是如何知道应该访问的是 d1 对象还是 d2 对象呢?那么这⾥就要看到 C++ 给了 ⼀个隐含的 this 指针解决这⾥的问题
  • C++ 规定不能在实参和 形参 的位置显⽰的写 this指针 (编译时编译器会处理),但是可以在函数体内显 ⽰使⽤ this指针
class Date
{
public:void Init(int year, int month, int day){this->year = year;this->month = month;this->day = day;}void Print(){cout << year << "/" << month << "/" << day << endl;}private:int year;int month;int day;
};
int main()
{Date d1, d2;d1.Init(2025, 5, 1);d2.Init(2025, 5, 2);d1.Print();d2.Print();return 0;
}

思考:d1、d2 调用的是同一个 Print,执行的是同一个函数,参数相同,那为什么输出的值不同?

我们先前调用同一个函数,执行出的结果不同,是因为我们传入了不同的参数

编译阶段,编译器为我们处理隐藏过程。实际上,我们调用同一个函数 Print() 执行出了不同结果,还是因为我们传入了不同参数

在这里插入图片描述


同样地,

在这里插入图片描述

this 本身无法被修改:this = nullptr(false)


3.1常量指针与指针常量

  • 常量指针与指向常量的指针

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


验证 this 指针指向 d1/d2对象地址:
在这里插入图片描述


3.2面试真题

在这里插入图片描述


答案:

正常运行

在这里插入图片描述

Print() 编译时确定地址,不存在 对空指针进行解引用的行为


在这里插入图片描述


对象 p 的作用:

  • 搜查、核对成员函数的出处
  • 指针所指向的对象(或对象)传递 this指针

在这里插入图片描述


  • 编译错误:语法问题,因此对于空指针的解引用(运行错误)一定不会触及语法编译的问题

  • 链接错误:语法规则符合,但存在函数或变量只声明,未定义行为

  • 运行错误:行为/功能错误

在这里插入图片描述


答案:

运行崩溃

在这里插入图片描述

(*p).Print(); 同理


在这里插入图片描述


解决方法:使 指针p 指向一个有效对象

C++A aa;A* p = &aa;//或 A* p = new A();

在这里插入图片描述


​ 常量区(语言层面) - 代码段(或叫数据段 - 操作系统角度)(函数被编译成指令后,存储在常量区)

​ 代码段:将函数编译好的代码指令(因此代码指令存储在常量区/代码段)

this指针 所存放的区域中,this指针 存放在对象中这一选项或许会有些许疑虑,但很简单,如果其存放在对象中,那么 sizoef(指针) == 4;这就与我们前面提到的 sizeof(p)(或sizeof(Person))== 1; 背道而驰了,因此,可论证: this指针 并不存储在实例对象中


在这里插入图片描述


this指针 是形式参数,严格一点是存储在 栈和寄存器

3.3浅识寄存器 esp/ebp

在这里插入图片描述


四、C++与C语言实现Stack对比

⾯向对象三⼤特性:封装、继承、多态,下⾯的对⽐我们可以初步了解⼀下封装。 通过下⾯两份代码对⽐,我们发现 C++ 实现 Stack 形态上还是发⽣了挺多的变化,底层和逻辑上没啥变化

以栈为例,C++ 对栈的各项操作进行了严格封装(减少了 C语言 多样化,但易错误的代码形态),而 C语言 则更依赖于程序员应对形式多样化代码能力的素质

CSTack st;//访问栈顶元素,方式一(直接调用函数 - 推荐):st.STop();//方式二:st.arr[st.top - 1];方式二:存在一定的不安全性,比如数组越界、0 - 1 == -1 等情况 

  • C++ 中数据和函数都放到了类⾥⾯,通过 访问限定符 进⾏了限制,不能再随意通过对象直接修改数 据,这是 C++封装 的⼀种体现,这个是最重要的变化。这⾥的 封装 的本质是⼀种更严格规范的管理,避免出现乱访问修改的问题 。当然 封装 不仅仅是这样的,我们后⾯还需要不断的去学习

  • C++ 中有⼀些相对⽅便的语法,⽐如 Init 给的缺省参数会⽅便很多,成员函数每次不需要传对象地址,因为 this指针 隐含的传递了,⽅便了很多,使⽤类型不再需要 typedef ⽤类名就很⽅便


在这里插入图片描述

🌟 各位看官好我是工藤新一¹呀~

🌈 愿各位心中所想,终有所致!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/80721.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/80721.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/80721.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java中进阶并发编程

第一章、并发编程的挑战 并发和并行&#xff1a;指多线程或多进程 线程的本质&#xff1a;操作系统能够进行运算调度的最小单位&#xff0c;是进程&#xff08;Process&#xff09;中的实际工作单元 进程的本质&#xff1a;操作系统进行资源分配和调度的基本单位&#xff0c…

《 指针变量类型与内存访问:揭秘背后的奥秘》

&#x1f680;个人主页&#xff1a;BabyZZの秘密日记 &#x1f4d6;收入专栏&#xff1a;C语言 &#x1f30d;文章目入 一、指针变量类型的基本概念二、指针类型与内存访问字节数的关系&#xff08;一&#xff09;整型指针&#xff08;二&#xff09;字符型指针&#xff08;三&…

mapbox进阶,使用mapbox-plugins插件加载饼状图

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.1 ☘️mapboxgl.Map style属性二、🍀使用mapbox-plugins插件加载饼状图1. ☘…

GraphicLayer与BusineDataLayer层级控制

补充说明&#xff1a; 当参与层级控制的元素是点型元素时&#xff0c;是无法参与ZIndex层级控制的&#xff0c;此时可以换个解决方案 1.给不同的高度值实现&#xff0c;元素间的层级控制覆盖 import * as mars3d from "mars3d"export let map // mars3d.Map三维地…

uniapp 百家云直播插件打包失败

打包错误日志 Android自有证书 打包失败 错误日志: https://app.liuyingyong.cn/build/errorLog/cf41a610-effe-11ef-88db-05262d4c3e5d原因&#xff1a;需要导入插件依赖 依赖地址&#xff1a;https://ext.dcloud.net.cn/plugin?id16289 百家云直播插件地址 直播插…

【C++】”如虎添翼“:模板初阶

泛型编程&#xff1a; C中一种使用模板来实现代码重用和类型安全的编程范式。它允许程序员编写与数据类型无关的代码&#xff0c;从而可以用相同的代码逻辑处理不同的数据类型。模板是泛型编程的基础 模板分为两类&#xff1a; 函数模板&#xff1a;代表了一个函数家族&#x…

十五、多态与虚函数

十五、多态与虚函数 15.1 引言 面向对象编程的基本特征&#xff1a;数据抽象&#xff08;封装&#xff09;、继承、多态基于对象&#xff1a;我们创建类和对象&#xff0c;并向这些对象发送消息多态&#xff08;Polymorphism&#xff09;&#xff1a;指的是相同的接口、不同的…

点云特征提取的两大经典范式:Voxel-based 与 Pillar-based

点云特征提取的两大经典范式&#xff1a;Voxel-based 与 Pillar-based 在点云处理领域&#xff0c;尤其是针对 3D 目标检测任务&#xff0c;特征提取是核心环节之一。目前&#xff0c;Voxel-based&#xff08;体素化&#xff09;和 Pillar-based&#xff08;柱状化&#xff09…

前苹果首席设计官回顾了其在苹果的设计生涯、公司文化、标志性产品的背后故事

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

web 自动化之 selenium 元素四大操作三大切换等待

文章目录 一、元素的四大操作二、三大切换&等待1、切换窗口:当定位的元素不在当前窗口&#xff0c;则需要切换窗口2、切换iframe&#xff1a;当定位的元素在frame/iframe&#xff0c;则需要切换3、切换弹出窗口 一、元素的四大操作 1、输入 2、点击 3、获取文本 4、获取属…

window server 2012安装sql server2008 r2

执行sql server2008 r2安装目录下的setup 选择运行程序而不获取帮助 然后就是让人绝望的 只能先搞这个了&#xff0c;F*微软&#xff0c;自家软件不让正常安装 打开服务器管理器->添加角色和功能->选择Web 服务&#xff08;IIS&#xff09;->添加.NET Framework3.5 然…

【K8S学习之生命周期钩子】详细了解 postStart 和 preStop 生命周期钩子

0. 参考 Kubernetes容器生命周期 —— 钩子函数详解&#xff08;postStart、preStop&#xff09; - 人艰不拆_zmc - 博客园详解Kubernetes Pod优雅退出 - 人艰不拆_zmc - 博客园 1. Kubernetes 生命周期钩子概述 在 Kubernetes 中&#xff0c;生命周期钩子&#xff08;Lifec…

测试文章标题01

模型上下文协议&#xff08;Model Context Protocol, MCP&#xff09;深度解析 一、MCP的核心概念 模型上下文协议&#xff08;Model Context Protocol, MCP&#xff09;是一种用于规范机器学习模型与外部环境交互的标准化框架。其核心目标是通过定义统一的接口和数据格式&am…

kubuntu系统详解

Kubuntu 系统深度解析&#xff08;从系统架构到用户体验&#xff09; 一、定位与核心特性 Kubuntu 是 Ubuntu 的官方 KDE 衍生版&#xff0c;基于 Ubuntu 的稳定底层&#xff08;Debian 技术栈&#xff09;&#xff0c;搭载 KDE Plasma 桌面环境&#xff0c;主打 “功能丰富、…

cURL:通过URL传输数据的命令行工具库介绍

文章目录 1. 什么是 curl&#xff1f;2. 下载与安装 curl3. curl 的常见用法3.1 获取网页内容3.2 下载文件3.3 发送 POST 请求&#xff08;带表单数据&#xff09;3.4 发送带 JSON 的 POST 请求 1. 什么是 curl&#xff1f; cURL&#xff08;CommandLine URL&#xff09;是非常…

从零搭建AI工作站:Gemma3大模型本地部署+WebUI配置全套方案

文章目录 前言1. 安装Ollama2.Gemma3模型安装与运行3. 安装Open WebUI图形化界面3.1 Open WebUI安装运行3.2 添加模型3.3 多模态测试 4. 安装内网穿透工具5. 配置固定公网地址总结 前言 如今各家的AI大模型厮杀得如火如荼&#xff0c;每天都有新的突破。今天我要给大家安利一款…

Element Plus对话框(ElDialog)全面指南:打造灵活弹窗交互

&#x1f4cc; 开篇导语 对话框是Web应用中实现用户交互的核心组件之一&#xff0c;常用于信息确认、表单提交或详情展示。Element Plus的ElDialog组件以高扩展性和优雅动效著称&#xff0c;支持高度定制化开发。本文将从基础配置到进阶技巧&#xff0c;手把手教你掌握对话框组…

解决WSL、Ubuntu的.ico图标不正确显示缩略图

解决WSL、Ubuntu的.ico图标不正确显示缩略图 问题描述 Win10系统中由于更新了某些软件&#xff0c;篡改了默认的图像显示软件&#xff0c;导致WSL等软件未能成功显示图标&#xff0c;表现如下&#xff1a; 解决方法 将ico文件的默认打开方式更改为“画图”&#xff0c;如下…

[数据结构高阶]并查集初识、手撕、可以解决哪类问题?

标题&#xff1a;[数据结构高阶]并查集初识、手撕、可以解决哪类问题&#xff1f; 水墨不写bug 文章目录 一、认识并查集二、模拟实现并查集三、用并查集解决问题1、[省份的数量](https://leetcode.cn/problems/number-of-provinces/)2、[等式方程的可满足性](https://leetcode…

如何快速入门大模型?

学习大模型的流程是什么 &#xff1f; 提示词工程&#xff1a;只需掌握提问技巧即可使用大模型&#xff0c;通过优化提问方式获得更精准的模型输出套壳应用开发&#xff1a;在大模型生态上开发业务层产品&#xff08;如AI主播、AI小助手等&#xff09;&#xff0c;只需调用API…