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

【C++】C++类和对象1:从struct到class,揭开面向对象编程的第一层面纱

相关专栏【Linux专栏】【C语言专栏】【测试专栏】【MySQL专栏】【C 专栏】 相关文章推荐【C】初识C写给零基础小白的入门指南【Linux】小白也能学会TCP Socket编程超详细入门教程【测试】软件测试必读一文搞懂BUG的生命周期与管理技巧【C语言】一文吃透C语言分支循环中的rand、srand与time函数很高兴你点开这篇文章✨这里会持续更新我喜欢的内容关注我一起慢慢变好呀 点赞 ⭐ 收藏 评论文章目录前言一、类的定义格式1.1 一个简单的Stack类1.2 访问限定符二、struct vs class三、成员变量的命名规范四、类域与声明定义分离4.1 什么是类域4.2 声明和定义分离五、实例化从类到对象六、对象的大小计算6.1 成员函数不占对象空间6.2 对象大小计算规则七、this指针7.1 this指针的本质mark stylebackground: #ffe4e1; padding: 2px 4px; border-radius: 3px; 在C中成员函数被编译时编译器会隐式地添加一个参数指向当前对象的指针this。 /mark7.2 this指针的特性7.3 经典面试题空指针调用成员函数**结论空指针可以调用不访问成员变量的成员函数但不能调用访问成员变量的成员函数。**八、知识点汇总九、总结十、本文所有的代码前言如果你刚从C语言的结构体struct来到C可能会问C的类class到底是什么它和struct有什么区别为什么类里面既能放变量又能放函数还有那个神秘的this指针又是怎么回事 带着疑问我们从一个简单的Stack类和Date类出发一步步拆解C类的核心概念。你会学到public和private到底在保护什么类的声明和定义为什么要分开写对象在内存里长什么样占多少字节this指针是编译器偷偷塞给你的秘密武器一、类的定义格式1.1 一个简单的Stack类类定义的格式classStack{// 类的方法/成员函数voidInit();// 开头没有访问限定符默认为privatepublic:voidPush(intx);intTop();voidDestroy();//public内的成员可直接访问直到下一个访问修饰符的出现private:// 类的属性/成员变量int*arr;inttop;intcapacity;};//到 } 结束1.2 访问限定符限定符含义public公开的类内外都可以访问private私有的只能在类内部访问protected受保护的类内部和派生类可访问继承时用到规则类中如果没有写访问限定符默认是private访问限定符的作用范围从它出现开始到下一个限定符或类结束为止intmain(){Stack st;st.Push(1);// ✅ public可以访问st.Init();// ❌ private无法访问st.arr;// ❌ private无法访问return0;}二、struct vs classC兼容C语言的struct同时引入了class。对比项structclass默认访问权限publicprivate使用场景通常用于简单的数据聚合通常用于完整的类设计// C中的struct默认publicstructDate{voidInit(intyear,intmouth,intday){_yearyear;_mouthmouth;_dayday;}private:int_year;int_mouth;int_day;};// 链表节点的写法对比typedefstructListNodeC// C风格{intval;structListNodeC*next;}LTNodeC;structListNodeCPP// C风格{intval;ListNodeCPP*next;// 不需要重复写struct};建议用class定义类用struct定义简单的数据集合。三、成员变量的命名规范为了避免成员变量和函数参数冲突C中常见的命名习惯classDate{public:voidInit(intyear,intmouth,intday){_yearyear;// 成员变量加下划线前缀_mouthmouth;_dayday;}private:int_year;// 方式1_yearintmouth_;// 方式2mouth_intm_day;// 方式3m_day};常见风格1、_year前缀下划线2、year_后缀下划线3、m_yearm前缀选择一种保持一致即可。四、类域与声明定义分离4.1 什么是类域类中的成员变量和函数属于类域。编译器查找一个名字时会按照局部域 - 全局域 - 类域的顺序查找。4.2 声明和定义分离成员函数可以在类内声明在类外定义。类外定义时需要指定类域。classStack{public:voidInit(intn4);// 声明private:int*arr;inttop;intcapacity;};// 类外定义必须加 Stack:: 指定类域voidStack::Init(intn){arr(int*)malloc(sizeof(int)*n);if(arrnullptr){perror(malloc申请空间失败);return;}capacityn;top0;}如果不指定类域会怎样voidInit(intn)// ❌ 编译器把Init当成全局函数找不到arr等成员{arr(int*)malloc(...);// 报错arr未定义}五、实例化从类到对象类是一种抽象描述定义了有哪些成员变量和成员函数。成员变量只是声明不分配空间。对象用类类型在物理内存中创建的具体实体。实例化对象时才会给成员变量分配空间。classDate{public://初始化函数给日期类的成员变量赋值voidInit(intyear,intmouth,intday){//给类的私有成员private_year/_mouth/_day赋值_yearyear;_mouthmouth;_dayday;}private:int_year;// 声明还未分配空间int_mouth;int_day;};intmain(){Date d1;// 实例化对象d1此时才分配空间Date d2;// 实例化对象d2分配独立的空间return0;}类比类 建筑设计图对象 根据图纸盖出来的房子。六、对象的大小计算6.1 成员函数不占对象空间对象中只存储成员变量成员函数存储在代码段所有对象共享。classA{public:voidPrint(){cout_chendl;}private:char_ch;int_i;};----------------------------------------classB{public:voidPrint(){//...}};----------------------------------------classC{};intmain(){A a;B b;C c;coutsizeof(a)endl;// 8char对齐后占4 int占4coutsizeof(b)endl;// 1空类占1字节用于标识对象地址coutsizeof(c)endl;// 1空类占1字节}6.2 对象大小计算规则规则说明只计算成员变量成员函数不计入内存对齐和C语言结构体对齐规则一致空类占1字节用于区分不同的空对象七、this指针7.1 this指针的本质在C中成员函数被编译时编译器会隐式地添加一个参数指向当前对象的指针this。类的成员函数中访问成员变量本质都是通过 this 指针访问的classDate{public:voidInit(intyear,intmouth,intday){_yearyear;_mouthmouth;_dayday;}};// 编译器实际处理的形式classDate{public:voidInit(Date*constthis,intyear,intmouth,intday){this-_yearyear;this-_mouthmouth;this-_dayday;}};// 调用时Date d1;d1.Init(2026,3,22);// 编译器转换为d1.Init(d1, 2026, 3, 22);7.2 this指针的特性特性说明类型ClassName* const this指针本身不可改指向的内容可改传递方式编译器自动传递不需要程序员手动传存储位置通常是寄存器如ECX或栈是否可以为空不访问成员变量时this可以是nullptr7.3 经典面试题空指针调用成员函数classA{public:voidPrint(){coutA::Print()endl;// 没有访问成员变量}voidPrintA(){cout_aendl;// 访问了成员变量}private:int_a1;};intmain(){A*pnullptr;p-Print();// ✅ 可以运行因为没有解引用this// p-PrintA(); // ❌ 崩溃因为this是nullptr访问_a相当于this-_areturn0;}结论空指针可以调用不访问成员变量的成员函数但不能调用访问成员变量的成员函数。八、知识点汇总知识点核心要点访问限定符public公开、private私有、protected保护默认权限class默认privatestruct默认public类域查找顺序局部 → 全局 → 类域声明定义分离类外定义需加类名::指定类域实例化类不占空间对象实例化时分配空间对象大小只算成员变量遵循内存对齐空类占1字节this指针编译器隐式传递的指向当前对象的指针空指针调用不访问成员变量时可以访问则会崩溃九、总结访问限定符实现了封装让代码更安全类域影响了编译器查找名字的规则实例化是从模型到实体的过程对象大小只包含成员变量不包含成员函数this指针是编译器在幕后帮我们干的活十、本文所有的代码#define_crt_secure_no_warnings1#includestring#includeiostreamusingnamespacestd;////类定义的格式classstack{//类的方法/成员函数voidinit();//开头没有访问限定符修饰则默认为privatepublic:voidpush(intx);inttop();voiddestroy();//public内的成员可直接访问直到下一个访问修饰符的出现也就是下面的privateprivate://类的属性/成员变量int*arr;inttop;intcapacity;//后面没有访问限定符出现时到 } 结束};intmain(){stack st;st.push(1);st.top();st.init();//err:无法访问 private 成员st.arr;//err:无法访问 private 成员return0;}////////////////////////////////////////////////////////////////////////////////////////classdate{public:voidinit(intyear,intmouth,intday)//下划线_名称_year,_mouth,_day是为了怕起冲突所加的特殊标记//避免输入year时系统不知道用publi的还是private的{_yearyear;_mouthmouth;_dayday;}private://为了区分成员变量一般习惯上在成员变量上加一个特殊标记如在前面或后面加 _ 或 m开头int_year;//_year,year_,myearint_mouth;int_day;};intmain(){date date;date.init(2026,3,22);return0;}structdate{voidinit(intyear,intmouth,intday){_yearyear;_mouthmouth;_dayday;}private:int_year;int_mouth;int_day;};//c兼容c中struct的用法// struct 定义类时没有被访问限定符修饰时默认是privatetypedefstructlistnodec{intval;structlistnodec*next;}ltnodec;structlistnodecpp{intval;listnodecpp*next;};intmain(){date date;date.init(2026,3,22);return0;}//stack(类域)//类域影响的是编译的查找规则下面程序中init//1.如果不指定类域stack那么编译器就会把init当成全局函数编译时找不到arr等成员的声明/定义在哪里就会报错//2.指定类域stack就是知道init是成员函数当前域找不到arr等成员就会到类域中去找classstack{public://成员函数voidinit(intn4);private://成员变量int*arr;inttop;intcapacity;};//////////////////////////////////////////////////////////////////////////////////////////声明和定义分离需要指定类域//void init();//err:由于没指定类域stack,则当成全局函数//但是在全局中和局部中均没有arr等成员的声明和定义,则会报错voidstack::init(intn)//此时指定了类域后除了全局和部局编译器还会在指定类域中查找成员{arr(int*)malloc(sizeof(int)*n);if(arrnullptr){perror(malloc申请空间失败咯!);return;}capacityn;top0;}intmain(){stack st;st.init();return0;}////实例化用类类型在物理内存中创建对象的过程////类是对象进行一种抽象描述是一个模型一样的东西限定了类有哪些成员变量////这些成员变量只是声明没有分配空间用类实例化出对象时才会分配空间classdate{public://初始化函数给日期类的成员变量赋值voidinit(intyear,intmouth,intday){//给类的私有成员private_year/_mouth/_day赋值_yearyear;_mouthmouth;_dayday;}voidprint(){cout_year/_mouth/_day;}private://加了static就变成了静态成员变量属于类本身所有对象公用一份_yearstaticint_year;//普通成员变量属于每个对象每个对象都有自己独立的_mouth,_dayint_mouth;int_day;};//静态成员变量不能在类内初始化必须在类外、全局作用域初始化//格式为 类型 类名::静态成员名 初始值;intdate::_year0;intmain(){//date类实例化出对象d1和d2date d1;date d2;d1.init(2026,3,22);d1.print();d2.init(2026,3,22);d2.print();return0;}/////计算一下a/b/c实例化的对象多大classa{public:voidprint(){cout_chendl;}private:char_ch;int_i;};classb{public:voidprint(){//....}};classc{};intmain(){a a;b b;c c;coutsizeof(a)endl;coutsizeof(b)endl;coutsizeof(c)endl;return0;}////this指针////类的成员函数中访问成员变量本质都是通过 this 指针访问的////如 init 函数中给 _year 赋值this-_year year;classdate{public:voidinit(intyear,intmouth,intday)//void init(date* const this,int year,int mouth,int day){_yearyear;_mouthmouth;_dayday;//this-_year year;//this-mouth mouth;//this-_day day;}voidprint()//这是我们写代码时的简洁写法//void print(date* const this)这是编译器底层处理的形式//this是指向当前调用该函数的date对象的指针{cout_year/_mouth/_dayendl;//coutthis-_year/this-_mouth/this-_dayendl;}private:staticint_year;int_mouth;int_day;};intmain(){//date类实例化出对象d1和d2date d1;date d2;d1.init(2026,3,22);//d1.init(d1,2026,3,22);d1.print();//d1.print(d1);d2.init(2026,3,22);//d2.init(d2,2026,3,22)d2.print();//d2.print(d2);return0;}classa{public:voidprint(){couta::print()endl;//cout_aendl;}private:int_a1;};intmain(){a*pnullptr;p-print();//p-_a1;return0;}下一篇我们继续学习Date类的设计与实现运算符重载拷贝构造函数流插入和流提取cout、cin谢谢你看到这里呀如果喜欢这篇内容点个关注下次更新不迷路✨ 点赞 ⭐ 收藏 评论
http://www.zskr.cn/news/1381091.html

相关文章:

  • Taotoken Token Plan 套餐详解与适用场景选择建议
  • 如何选择靠谱的德州英语背单词工具:从用户评价到实际效果全解析
  • 具身智能 | 浅谈具身智能与低空经济融合
  • 高校科研团队如何通过Taotoken管理多个课题组的AI模型使用
  • 宽带隙的半导体
  • 我们为什么做 AR1106:把“声音方向”真正变成设备能力
  • 大模型集体“下海”赚钱:2026年AI生死战已打响,免费时代正式终结?
  • Iwara视频下载神器:2025终极指南,一键批量下载全攻略
  • 3步解决Windows热键冲突的终极技术方案
  • 【Midjourney辉光效果终极指南】:20年AI视觉工程师亲授7种工业级发光参数组合,92%新手3天内复现Dribbble爆款效果
  • 5分钟完成HS2-HF_Patch汉化补丁安装:免费中文翻译终极指南
  • 打卡信奥刷题(3314)用C++实现信奥题 P9183 [USACO23OPEN] FEB B
  • 打卡信奥刷题(3316)用C++实现信奥题 P9185 [USACO23OPEN] Rotate and Shift B
  • 员工手册与制度问答机器人深度评测:让 HR 从重复答疑中解放
  • BiliDownloader:解决B站视频本地化收藏的技术方案
  • Cursor Pro 免费升级终极指南:突破使用限制的完整解决方案
  • 2026年6年林芝采暖设备市场调研:TOP5地暖品牌综合实力与性价比对比报告 - 博客万
  • 别再傻傻分不清!电源纹波和噪声的实测对比与降噪实战(附示波器实测图)
  • 3大突破性功能:用HiveWE革新你的魔兽争霸III地图创作体验
  • 使用Taotoken CLI工具一键配置多开发环境下的统一模型接入点
  • 如何解决Umi-OCR启动崩溃:OCR引擎插件缺失的快速修复指南
  • Claude 4.0容器化部署实战:从零构建高可用、低延迟、合规审计就绪的私有AI服务(附完整Helm Chart与安全加固Checklist)
  • PlayAI语音评测全链路方法论(含开源评估Pipeline与自动化脚本)
  • 3步掌握ChartGPT:AI驱动的自然语言图表生成架构深度解析
  • 终极指南:如何用WarcraftHelper让魔兽争霸3在现代电脑上焕发新生 [特殊字符]
  • 最危险的不是 OpenAI 抢你,而是 Anthropic 悄悄把你做成它的一个功能
  • 机器学习力场攻克Peierls相变动力学:从对称性描述符到畴生长标度律
  • WarcraftHelper:让经典魔兽争霸3完美适配现代电脑的终极解决方案
  • 数字合成器d-FORMANT:从模拟经典到数字复刻的工程实践
  • 大模型测试新范式:Claude端到端验证的5层断言体系(语义一致性/上下文连贯性/安全边界/成本阈值/时序鲁棒性)