C++ 类和对象入门:类的定义、封装、对象大小与 this 指针
C 类和对象入门类的定义、封装、对象大小与 this 指针C 从 C 语言走向面向对象编程第一道真正的门槛就是“类和对象”。很多人刚开始会把class理解成“带函数的结构体”这个说法有一点直观但并不完整。类不仅能把数据和操作放在一起还能通过访问限定符控制哪些内容对外开放哪些细节隐藏在内部。这篇文章从最基础的类定义开始逐步讲清楚类成员、访问限定符、类域、对象实例化、对象大小、内存对齐、this指针以及 C 写法和 C 写法在组织代码上的差异。一、类是什么类可以理解为一种自定义类型用来描述一类对象应该拥有哪些数据以及能执行哪些操作。在类中变量称为成员变量也可以叫属性函数称为成员函数也可以叫方法class是定义类的关键字类定义结束后的分号不能省略。一个简单的栈可以写成这样#includecassert#includecstdio#includecstdlib#includeiostreamclassStack{public:voidInit(intn4){_arraystatic_castint*(std::malloc(sizeof(int)*n));if(_arraynullptr){std::perror(malloc failed);return;}_capacityn;_top0;}voidPush(intx){assert(_array!nullptr);if(_top_capacity){intnew_capacity_capacity0?4:_capacity*2;int*tmpstatic_castint*(std::realloc(_array,sizeof(int)*new_capacity));if(tmpnullptr){std::perror(realloc failed);return;}_arraytmp;_capacitynew_capacity;}_array[_top]x;}intTop(){assert(_top0);return_array[_top-1];}voidPop(){assert(_top0);--_top;}boolEmpty(){return_top0;}voidDestroy(){std::free(_array);_arraynullptr;_top0;_capacity0;}private:int*_array;int_capacity;int_top;};intmain(){Stack st;st.Init();st.Push(1);st.Push(2);std::coutst.Top()std::endl;st.Destroy();return0;}编译运行g stack_demo.cpp-stdc11-ostack_demo ./stack_demo预期输出2这里的_array、_capacity、_top是成员变量Init、Push、Top、Pop、Destroy是成员函数。成员变量前面加_不是语法要求只是一种常见命名习惯用来区分成员变量和普通局部变量。注意这个示例为了贴近入门阶段仍然使用malloc/realloc/free管理空间。真正进入 C 对象管理后会继续学习构造函数、析构函数、new/delete、RAII 等更自然的写法。二、class 和 struct 有什么区别C 兼容 C 中struct的用法同时也增强了struct在 C 中struct里面也可以定义成员函数。structListNode{voidInit(intx){valx;nextnullptr;}intval;ListNode*next;};class和struct都可以定义类最直接的区别是默认访问权限不同写法默认访问权限classprivatestructpublic实际开发中一个简单的数据聚合类型常用struct更强调封装和行为的类型常用class。这不是硬性规定但能让代码意图更清楚。三、访问限定符封装从这里开始C 提供三个访问限定符限定符类外能否直接访问说明public可以通常放对外接口private不可以通常放实现细节和成员变量protected不可以主要在继承中体现价值访问限定符的作用范围从它出现的位置开始一直到下一个访问限定符出现或者类定义结束。classDate{public:voidInit(intyear,intmonth,intday){_yearyear;_monthmonth;_dayday;}voidPrint(){std::cout_year/_month/_daystd::endl;}private:int_year;int_month;int_day;};这里_year、_month、_day被放在private区域类外不能直接修改只能通过Init、Print这样的公开成员函数使用。很多初学者会问既然成员变量最终还是要被函数访问为什么不直接设成public原因在于封装。成员变量直接暴露后外部代码可以随意改对象状态很容易绕过必要检查。成员函数作为接口可以控制修改规则让对象始终保持合理状态。四、类域类也有自己的作用域类定义了一个新的作用域。成员函数如果在类外定义需要使用类名::函数名指明它属于哪个类。classStack{public:voidInit(intn4);private:int*_array;int_capacity;int_top;};voidStack::Init(intn){_arraystatic_castint*(std::malloc(sizeof(int)*n));if(_arraynullptr){std::perror(malloc failed);return;}_capacityn;_top0;}如果写成下面这样voidInit(intn){_capacityn;}编译器会把它当成普通全局函数。全局函数里找不到_capacity这个成员变量自然会报错。所以类外定义成员函数时Stack::不是装饰而是在告诉编译器这个函数属于Stack的类域。五、实例化类只是设计图对象才占空间类本身只是对对象的抽象描述它规定对象有哪些成员变量和成员函数。真正占用内存的是通过类创建出来的对象这个过程叫实例化。Date d1;Date d2;d1.Init(2024,3,31);d2.Init(2024,7,5);可以把类理解成设计图把对象理解成按照设计图建出来的房子。设计图规定房间如何布局但设计图本身不能住人对象才真正拥有自己的数据空间。d1和d2都是Date类型对象它们有相同的成员函数但成员变量各自独立Date 类d1 对象d2 对象_year/_month/_day 一份数据_year/_month/_day 另一份数据Init/Print 代码只有一份这里有一个关键点对象中只存储成员变量不会为每个对象都存一份成员函数代码。成员函数编译后是指令存放在代码区域。不同对象调用同一个成员函数时函数代码是同一份只是传入的对象不同。六、对象大小成员变量、内存对齐和空类一个类对象大小主要由成员变量决定同时要满足内存对齐规则。#includeiostreamclassA{public:voidPrint(){std::cout_chstd::endl;}private:char_ch;int_i;};classB{public:voidPrint(){}};classC{};intmain(){std::coutsizeof(A)std::endl;std::coutsizeof(B)std::endl;std::coutsizeof(C)std::endl;return0;}A的大小不是简单的1 4 5因为要考虑内存对齐。常见平台上结果可能是 8。内存对齐可以简单理解为第一个成员从偏移量 0 开始后续成员要放在满足对齐要求的位置对象整体大小通常要对齐到最大对齐数的整数倍具体对齐数和编译器、平台设置有关。B和C没有成员变量但对象大小通常是 1。原因是对象必须有地址如果大小为 0就无法区分两个不同对象是否真实存在。这个 1 字节主要用于占位。七、this 指针成员函数如何知道操作哪个对象看下面这个类classDate{public:voidInit(intyear,intmonth,intday){_yearyear;_monthmonth;_dayday;}voidPrint(){std::cout_year/_month/_daystd::endl;}private:int_year;int_month;int_day;};如果有两个对象Date d1;Date d2;d1.Init(2024,3,31);d2.Init(2024,7,5);Init函数代码只有一份那它怎么知道当前要修改的是d1还是d2答案就是this指针。成员函数在调用时会隐式接收一个指向当前对象的指针。可以粗略理解成编译器把成员函数处理成类似下面的形式// 为了理解而写的示意不是实际源码写法voidInit(Date*constthis,intyear,intmonth,intday){this-_yearyear;this-_monthmonth;this-_dayday;}在成员函数内部_yearyear;本质上等价于this-_yearyear;this有几个特点this只能在成员函数内部使用调用成员函数时编译器自动传递当前对象地址不能在实参和形参位置显式写thisthis是类型* const指针本身不能被重新赋值this不存放在对象内部它是成员函数调用时的隐含参数。关于this在内存中的具体位置不要死记成某个固定区域。它作为隐含参数参与函数调用可能通过寄存器传递也可能按调用约定放到栈上取决于平台、编译器和优化设置。更重要的是理解this不是对象的一部分。八、空指针调用成员函数为什么危险有时会看到这样的代码classA{public:voidPrint(){std::coutA::Print()std::endl;}};intmain(){A*pnullptr;p-Print();return0;}某些环境下这段代码看起来可能能正常输出因为Print没有访问成员变量函数体没有真正解引用对象数据。但下面这个版本就危险得多classA{public:voidPrint(){std::coutA::Print()std::endl;std::cout_astd::endl;}private:int_a;};intmain(){A*pnullptr;p-Print();return0;}访问_a本质是通过this-_a访问成员变量而this此时是空指针程序很可能崩溃。更稳妥的结论是不要通过空指针调用成员函数。即使某些场景下“看起来能跑”也不是可靠写法更不能作为工程代码依赖。九、C 写法和 C 写法对比封装到底改变了什么用 C 写栈时常见形式是结构体加一组操作函数typedefintSTDataType;typedefstructStack{STDataType*a;inttop;intcapacity;}ST;voidSTInit(ST*ps);voidSTPush(ST*ps,STDataType x);voidSTPop(ST*ps);STDataTypeSTTop(ST*ps);intSTEmpty(ST*ps);voidSTDestroy(ST*ps);调用时每个函数都要显式传对象地址ST s;STInit(s);STPush(s,1);STPush(s,2);STDestroy(s);C 写法把数据和操作放进同一个类中classStack{public:voidInit(intn4);voidPush(intx);voidPop();intTop();boolEmpty();voidDestroy();private:int*_array;int_capacity;int_top;};调用时更像是“对象自己执行操作”Stack s;s.Init();s.Push(1);s.Push(2);s.Destroy();从底层逻辑看这两种写法做的事情差别并不大。C 成员函数隐式传递this相当于把 C 写法里反复传入的ST* ps隐藏起来了。真正重要的变化在于封装成员变量可以放到private中外部不能随便改对外只暴露public接口使用者不需要关心内部细节成员函数和成员变量聚合在一起代码组织更清晰默认参数、类域、this指针让调用方式更自然。这也是面向对象的第一层价值把数据和操作绑定起来并通过访问权限管理对象状态。十、常见问题与易错点1. 类定义后面的分号为什么不能省类定义本质上是在定义一种类型语法要求类体结束后必须有分号。少了分号后面的代码会被编译器错误解析。2. 成员函数定义在类里面有什么特点定义在类体内的成员函数默认具有内联属性。注意这只是给编译器的建议不代表一定展开。3.class中不写访问限定符会怎样class默认是privatestruct默认是public。如果类里直接写成员变量但忘了public类外访问时可能报访问权限错误。4. 对象里为什么不存成员函数成员函数编译后是代码指令不需要每个对象都存一份。对象中主要存储成员变量。不同对象调用同一成员函数时通过隐含的this指针区分当前对象。5. 空类为什么大小是 1空类没有成员变量但对象必须能被取地址并区分不同对象。给 1 字节是为了占位表示对象存在。6.this可以被修改吗不能。可以把this理解成类型* const this指针本身不能被重新赋值。但可以通过this修改对象成员前提是成员函数不是const成员函数。十一、总结类和对象是 C 从过程式编程走向面向对象编程的起点。入门阶段需要抓住几条主线类把成员变量和成员函数组织在一起public提供接口private隐藏实现细节类只是类型描述对象实例化后才真正占用内存对象中主要存成员变量成员函数代码只保留一份对象大小受成员变量和内存对齐影响空类大小通常为 1成员函数通过隐含的this指针区分当前对象C 的封装让数据修改更受控代码组织也更清晰。把这些基础理解透再继续学习构造函数、析构函数、拷贝构造、运算符重载和继承时就不会只是在背语法而能看懂 C 为什么要这样设计。

相关新闻

如何快速掌握Photon-GAMS光影包:面向Minecraft玩家的完整实战指南

如何快速掌握Photon-GAMS光影包:面向Minecraft玩家的完整实战指南

如何快速掌握Photon-GAMS光影包:面向Minecraft玩家的完整实战指南 【免费下载链接】Photon-GAMS Personal fork of Photon shaders 项目地址: https://gitcode.com/gh_mirrors/ph/Photon-GAMS 你是否厌倦了Minecraft原版那单调乏味的画面?想要一键…

2026/7/10 13:02:16阅读更多 →
UVa 645 File Mapping

UVa 645 File Mapping

题目描述 在图形用户界面出现之前,计算机用户常通过缩进形式查看目录结构。本题要求模拟文件系统的目录映射,给定一系列目录名(以 d 开头)和文件名(以 f 开头),以及目录结束标记 ],输…

2026/7/10 13:02:16阅读更多 →
一个独立站小白的建站成本实测:从Shopify到国内服务商,我踩过的坑和总结

一个独立站小白的建站成本实测:从Shopify到国内服务商,我踩过的坑和总结

背景我是做亚马逊FBA的,去年开始想搞一个独立站。原因很简单——亚马逊的佣金越来越高,而且客户数据我碰不到。你卖了多少单、客户是谁、复购率怎么样,所有这些信息都在亚马逊手里。长期来看,这就是个定时炸弹。但问题来了&#x…

2026/7/10 12:57:15阅读更多 →
3步快速解决Windows多显示器DPI缩放难题的完整方案

3步快速解决Windows多显示器DPI缩放难题的完整方案

3步快速解决Windows多显示器DPI缩放难题的完整方案 【免费下载链接】SetDPI 项目地址: https://gitcode.com/gh_mirrors/se/SetDPI 你是否曾为Windows多显示器DPI缩放问题而烦恼?想象一下这样的场景:你正沉浸在工作中,4K主显示器上的…

2026/7/10 14:02:32阅读更多 →
SPT-AKI存档编辑器:彻底解放你的塔科夫离线游戏体验

SPT-AKI存档编辑器:彻底解放你的塔科夫离线游戏体验

SPT-AKI存档编辑器:彻底解放你的塔科夫离线游戏体验 【免费下载链接】SPT-AKI-Profile-Editor Программа для редактирования профиля игрока на сервере SPT-AKI 项目地址: https://gitcode.com/gh_mirrors/sp/…

2026/7/10 14:02:32阅读更多 →
Danus:基于事实图记忆的数学推理智能体协同调度系统

Danus:基于事实图记忆的数学推理智能体协同调度系统

Danus:基于事实图记忆的数学推理智能体协同调度系统 论文原链接:https://arxiv.org/html/2607.06447v2 摘要 基于大语言模型(LLM)的数学推理智能体已能够攻克研究级数学难题,部分工作甚至解决公开数学猜想。但现有系统…

2026/7/10 14:02:32阅读更多 →
终极指南:如何在Windows电脑上完美体验酷安社区

终极指南:如何在Windows电脑上完美体验酷安社区

终极指南:如何在Windows电脑上完美体验酷安社区 【免费下载链接】Coolapk-UWP 一个基于 UWP 平台的第三方酷安客户端 项目地址: https://gitcode.com/gh_mirrors/co/Coolapk-UWP 你是否厌倦了在小屏幕上刷酷安?想要在电脑大屏上畅享酷安社区的全功…

2026/7/10 14:02:32阅读更多 →
智能人脸识别系统

智能人脸识别系统

人脸识别系统#ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <opencv2/opencv.hpp> #include <iostream> #include <math.h> #include<opencv2/face.hpp> #include <vector> #include <map> #include <QMessageB…

2026/7/10 14:02:32阅读更多 →
MZmine 3:开源质谱数据分析平台完全指南

MZmine 3:开源质谱数据分析平台完全指南

MZmine 3&#xff1a;开源质谱数据分析平台完全指南 【免费下载链接】mzmine3 mzmine source code repository 项目地址: https://gitcode.com/gh_mirrors/mz/mzmine3 MZmine 3是一款功能全面的免费开源质谱数据分析软件&#xff0c;专为代谢组学、脂质组学和蛋白质组学…

2026/7/10 13:57:32阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述&#xff1a;从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目&#xff0c;叫 skills4/skills &#xff0c;它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景&#xff1a;一个旨在展示或教授某种技能的仓库&#xff0c;本身却成了安…

2026/7/10 12:10:00阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示&#xff1a;因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战&#xff1a;从“黑箱预测”到“可信推理”2026年6月&#xff0c;第7届机器学习与趋势国际会议&#xff08;MLT 2026&#xff09;将在悉尼召开。会议议程中&#xff0c;“因果与可解释机器学习…

2026/7/10 12:29:21阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时&#xff0c;通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中&#xff0c;是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/10 4:59:05阅读更多 →
浏览器缓存行为深度解析:Chrome/Firefox/Safari 对 304 响应的 5 种触发场景对比

浏览器缓存行为深度解析:Chrome/Firefox/Safari 对 304 响应的 5 种触发场景对比

浏览器缓存行为深度解析&#xff1a;Chrome/Firefox/Safari 对 304 响应的 5 种触发场景对比当你在浏览器地址栏敲入一个网址时&#xff0c;背后可能隐藏着一场关于"要不要重新下载资源"的精密博弈。这场博弈的裁判是HTTP缓存机制&#xff0c;而304状态码则是这场博弈…

2026/7/10 0:00:01阅读更多 →
RoboWits:面向创造性问题求解的双臂机器人认知推理基准

RoboWits:面向创造性问题求解的双臂机器人认知推理基准

1. 项目概述&#xff1a;这不是又一个机器人抓取数据集&#xff0c;而是一次对“思考力”的压力测试 RoboWits——这个名字里藏着两个关键信号&#xff1a;“Robo”直指物理世界中的具身智能体&#xff0c;“Wits”则毫不掩饰地指向人类最核心的认知能力&#xff1a;机敏、判断…

2026/7/10 0:00:01阅读更多 →
5分钟完全指南:如何使用TegraRcmGUI图形化工具解锁Switch无限可能

5分钟完全指南:如何使用TegraRcmGUI图形化工具解锁Switch无限可能

5分钟完全指南&#xff1a;如何使用TegraRcmGUI图形化工具解锁Switch无限可能 【免费下载链接】TegraRcmGUI C GUI for TegraRcmSmash (Fuse Gele exploit for Nintendo Switch) 项目地址: https://gitcode.com/gh_mirrors/te/TegraRcmGUI TegraRcmGUI是一款专为Windows…

2026/7/10 0:00:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时&#xff0c;发现推理速度只有可怜的 1-2 FPS&#xff0c;而别人的演示视频却能跑到 30 FPS 以上&#xff0c;那么问题很可能不在模型本身&#xff0c;而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后&#xff0c;会直接使用官方示例…

2026/7/10 13:39:09阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一&#xff1a;为什么你需要了解 Coze 和 Dify&#xff1f;如果你对 AI 应用开发感兴趣&#xff0c;但一看到“大模型”、“智能体”、“工作流”这些词就头疼&#xff0c;觉得门槛太高&#xff0c;那这篇文章就是为你准备的。很多开发者&#xff0c;包括我自己&#…

2026/7/9 15:50:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会&#xff1a;配图一直是个让人头疼的问题。2026年&#xff0c;AI生图工具已经非常成熟了&#xff0c;但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1&#xff1a;速度之王2026年6月11日&#xff0c…

2026/7/9 14:14:17阅读更多 →