枣庄网站制作长沙网页制作企业

张小明 2026/1/4 4:18:57
枣庄网站制作,长沙网页制作企业,制作网页的素材图片及文字,中英双语网站源码hello#xff0c;这里是AuroraWanderll。 兴趣方向#xff1a;C#xff0c;算法#xff0c;Linux系统#xff0c;游戏客户端开发 欢迎关注#xff0c;我将更新更多相关内容#xff01;个人主页 这是类和对象系列的第二篇文章#xff0c;上篇指引#xff1a;类和对象(一…hello这里是AuroraWanderll。 兴趣方向C算法Linux系统游戏客户端开发 欢迎关注我将更新更多相关内容个人主页这是类和对象系列的第二篇文章上篇指引类和对象(一)之前由于第一次发布时篇幅过长可能导致阅读体验很差现在我把他按要点进行了适当拆分希望能帮助读者更好理解也方便自己复习。C类和对象–C重要基础入门知识二简易目录访问限定符与封装——面向对象的大门守卫类的实例化与对象模型——从蓝图到实体this指针——对象的自我认知第四个重要问题访问限定符与封装——面向对象的大门守卫通过前几个问题的讲解我们已经知道如何定义类了。但面向对象不仅仅是把数据和函数打包在一起更重要的是控制外界如何与我们的对象交互。这就是我们今天要讲的访问限定符和封装。一、访问限定符想象一下类的成员就像一栋建筑里的不同房间而访问限定符就是这些房间的门禁系统控制着谁可以进入哪个房间。而房间我们有三个分级权限按秘密性更高分别递增public公共的protected受保护的private私有的C提供了三种访问限定符cppclass BankAccount { private: // 金库区 - 只有银行内部人员可以进入 double balance; // 余额 string password; // 密码 protected: // 办公区 - 银行员工和经理可以进入 double calculateInterest(); // 计算利息 public: // 营业大厅 - 所有客户都可以使用 void deposit(double amount); // 存款 void withdraw(double amount); // 取款 double getBalance(); // 查询余额 };访问限定符详解1.private私有权限只能在类的内部访问用途隐藏实现细节保护敏感数据示例balance,password这些数据不应该被外部直接修改不过我们依然可以提供特定的get方法来让外界适当的访问数据后面说。2.protected保护权限在类内部和派生类中可访问用途为继承体系设计我们讲到继承时会详细说明在继承里常见。3.public公有权限在任何地方都可以访问用途提供对外的接口定义类与外界交互的方式重要规则作用域规则从访问限定符出现的位置开始到下一个访问限定符或类结束为止cppclass Example { public: int a; // public int b; // public private: int c; // private int d; // private public: int e; // public }; // 类结束默认访问权限class默认是privatestruct默认是public为了兼容C语言编译时检查访问权限只在编译阶段检查运行时没有任何区别二、封装面向对象的黑箱哲学什么是封装封装数据操作数据的方法访问控制对应成员变量成员函数访问限定符封装就是我们来造一个完整的类用一句话概括“隐藏实现细节只暴露必要的接口”现实世界的封装例子电脑的封装隐藏的CPU如何运算、内存如何管理、硬盘如何存储暴露的开机按钮、USB接口、显示器、键盘鼠标汽车的封装隐藏的发动机工作原理、变速箱机制、燃油喷射系统暴露的方向盘、油门、刹车、仪表盘用户管他那么多只管用就完了(使用但不考虑底层)代码示例没有封装 vs 有封装没有封装的糟糕设计// 糟糕所有数据都是public的 class Person { public: string name; int age; double salary; }; // 使用时可以直接修改可能出现不合理的数据 Person p; p.age -5; // 年龄可以是负数不合理 p.salary 100000; // 随便设置薪水不安全甚至在一个项目中的同事都有可能无意间改造了你的代码数据!这将导致你遭到无比严峻的惩罚良好的封装设计class Person { private: string name; int age; double salary; public: // 通过公共方法来访问和修改数据 void setAge(int newAge) { if (newAge 0 newAge 150) { // 数据验证 age newAge; } else { cout 无效的年龄 endl; } } void setSalary(double newSalary, bool isAdmin) { if (isAdmin) { // 权限检查 salary newSalary; } else { cout 无权修改薪水 endl; } } int getAge() const { return age; } string getName() const { return name; } // 注意没有提供getSalary()薪水信息对外隐藏 }; // 使用封装后的类 Person p; p.setAge(25); // 正确 p.setAge(-5); // 会被拒绝并提示错误 p.setSalary(50000, false); // 无权限操作被拒绝通过public方法来限制和管理用户访问数据的方式。如果你是游戏玩家你大概也会像我一样梦想着通过修改游戏货币来获得自己想要的角色和皮肤。可惜我们的游戏货币大概是private变量而游戏公司没给我们public的方法。三、封装带来的巨大好处1. 数据保护class BankAccount { private: double balance; public: void withdraw(double amount) { if (amount balance) { // 防止透支 balance - amount; } } };2. 实现灵活性class DataStorage { private: // 内部实现可以随时改变不影响外部使用者 vectorint data; // 今天用vector // 明天可以改成 mapint, int 或其他结构 public: void addData(int value) { data.push_back(value); } int getData(int index) { return data[index]; } };3. 易于维护当需要修改验证逻辑时只需要在一个地方修改void setAge(int newAge) { // 只需要在这里修改验证规则 if (newAge 0 newAge 120) { // 从150改为120 age newAge; } }4. 降低复杂度使用者不需要了解内部实现只需要知道接口怎么用// 使用者只需要知道 calculator.add(5, 3); // 结果是8 // 不需要知道 // - 是用CPU加法器实现的 // - 还是用位运算实现的 // - 有没有缓存机制节省了使用者的精力我们的软件因此更好用。四、封装的最佳实践1. 数据成员通常设为privateclass GoodDesign { private: int importantData; // 数据隐藏 public: // 通过方法访问 };2. 提供完整的Get/Set方法class Rectangle { private: double width; double height; public: double getWidth() const { return width; } void setWidth(double w) { if (w 0) width w; } double getHeight() const { return height; } void setHeight(double h) { if (h 0) height h; } // 提供有意义的业务方法而不仅仅是Get/Set double getArea() const { return width * height; } };这一点我们在所有面向对象的语言中都很常见例如java也通过类似的方式访问3. 构造函数初始化class Student { private: string name; int id; public: // 通过构造函数确保对象始终处于有效状态 Student(const string n, int i) : name(n), id(i) { // 可以在构造函数中进行验证 } };第五个重要问题类的实例化与对象模型——从蓝图到实体通过前面的学习我们已经知道如何设计蓝图类现在让我们看看如何把蓝图变成实体对象以及这些实体在内存中是如何存储的。一、类的实例化从蓝图到建筑什么是实例化类的实例化就是用类类型创建对象的过程。**生动的比喻**实例化就是我们按照类的定义这个建筑图纸来创建一个实际的类对象一栋实际的房子关键理解类本身不占空间class Person { public: void introduce() { cout 我叫 name 今年 age 岁 endl; } private: string name; int age; }; int main() { // 错误类本身没有空间不能直接访问成员 // Person::age 100; // 编译错误 // 正确必须先实例化对象 Person p1; // 创建第一个Person对象 Person p2; // 创建第二个Person对象 return 0; }重要结论类 设计图不占内存空间对象 实际建筑占用物理内存必须先实例化才能使用二、类对象模型对象在内存中的秘密当我们创建一个对象时它到底包含什么成员变量和成员函数是如何存储的三种可能的存储方式方式1对象包含所有成员变量函数对象A: [变量_a] [函数PrintA代码] 对象B: [变量_b] [函数PrintA代码] ← 重复存储浪费空间方式2对象包含变量和函数指针对象A: [变量_a] [指向PrintA的指针] 对象B: [变量_b] [指向PrintA的指针] ← 还是有多余的指针方式3对象只包含变量函数在代码区对象A: [变量_a] 对象B: [变量_b] 代码区: [PrintA函数代码] ← 只有一份所有对象共享真相验证通过sizeof来探究让我们用代码来验证计算机到底采用哪种方式#include iostream using namespace std; // 类中既有成员变量又有成员函数 class A1 { public: void f1() {} private: int _a; }; // 类中仅有成员函数 class A2 { public: void f2() {} }; // 空类 class A3 {}; int main() { cout sizeof(A1): sizeof(A1) endl; // 输出多少 cout sizeof(A2): sizeof(A2) endl; // 输出多少 cout sizeof(A3): sizeof(A3) endl; // 输出多少 return 0; }运行结果sizeof(A1): 4 // 只有一个int成员变量 sizeof(A2): 1 // 没有成员变量但空类不能为0 sizeof(A3): 1 // 空类重要结论对象只存储成员变量成员函数存放在公共的代码段空类大小为1字节为了确保每个对象在内存中有唯一的地址计算类大小 所有成员变量大小之和考虑内存对齐三、结构体内存对齐规则为什么sizeof(A1)是4而不是其他值这就涉及到内存对齐。为什么要内存对齐性能优化CPU读取对齐的数据更快硬件要求某些架构要求数据必须对齐访问对齐规则重要第一个成员在结构体偏移量0处其他成员要对齐到min(成员大小, 编译器默认对齐数)的整数倍地址VS默认对齐数 8Linux通常没有默认对齐数按成员自身大小对齐结构体总大小 最大对齐数的整数倍嵌套结构体对齐到嵌套结构体自身最大对齐数的整数倍实战分析struct Example1 { char a; // 1字节偏移0 int b; // 4字节对齐到4的倍数偏移4 double c; // 8字节对齐到8的倍数偏移8 // 总大小8(c) 8 16是8的倍数 ✓ }; // sizeof(Example1) 16 struct Example2 { int a; // 4字节偏移0 char b; // 1字节偏移4 short c; // 2字节对齐到2的倍数 // 总大小4127但要是4的倍数 → 8 }; // sizeof(Example2) 8 struct Example3 { char a; // 1字节偏移0 // 填充3字节 int b; // 4字节偏移4 char c; // 1字节偏移8 // 填充7字节因为嵌套结构体最大对齐数是8 struct Inner { double d; // 8字节 } inner; }; // sizeof(Example3) 24关于这一知识点的重要问题1. 结构体怎么对齐为什么要进行内存对齐对齐方法按成员声明顺序依次放置每个成员对齐到特定边界最后补齐到最大对齐数的整数倍对齐原因性能对齐后CPU可以用更少的周期读取数据移植性避免在不同平台出现兼容性问题硬件限制某些CPU无法访问未对齐的内存2. 如何指定对齐参数// 指定按4字节对齐 #pragma pack(4) struct AlignedStruct { char a; // 1字节 int b; // 4字节现在按4对齐而不是8 double c; // 8字节但受pack(4)影响按4对齐 }; #pragma pack() // 恢复默认对齐 // C11方式 struct alignas(8) MyStruct { int a; char b; };注意不能任意对齐如3、5字节必须是2的幂次方。3. 大小端问题什么是大小端大端模式高位字节存储在低地址人类阅读顺序小端模式低位字节存储在低地址Intel/ARM常用测试方法#include iostream using namespace std; void checkEndian() { int num 0x12345678;//从左往右字节越来越低 char* ptr (char*)num//强制按字节访问我们的整形 if (*ptr 0x78) { cout 小端模式 endl; // 78在低地址 } else { cout 大端模式 endl; // 12在低地址 } }需要考虑大小端的场景网络编程网络字节序是大端需要htonl/ntohl转换文件格式某些文件格式指定了字节序硬件交互与特定硬件设备通信时跨平台数据交换不同架构的系统间传输数据底层对齐层面内存对齐提升性能大小端影响本讲数据存储最后一个重要问题this指针——对象的自我认知通过前面的学习我们已经知道如何定义类、创建对象但有一个关键问题当多个对象调用同一个成员函数时函数如何知道自己在操作哪个对象这就是this指针要解决的核心问题一、this指针的引出对象身份的困惑问题场景class Date { public: void Init(int year, int month, int day) { _year year; // 问题这个_year属于哪个对象 _month month; // d1的month还是d2的month _day day; } void Print() { cout _year - _month - _day endl; } private: int _year; int _month; int _day; }; int main() { Date d1, d2; d1.Init(2022, 1, 11); // 设置d1的日期 d2.Init(2022, 1, 12); // 设置d2的日期 d1.Print(); // 打印d1 d2.Print(); // 打印d2 return 0; }关键问题同一个Init函数如何知道现在是要初始化d1还是d2二、this指针的真相编译器的额外处理编译器在背后做了什么实际上编译器把我们的成员函数翻译成了这样// 我们写的 void Init(int year, int month, int day) { _year year; _month month; _day day; } // 编译器处理的 void Init(Date* this, int year, int month, int day) { this-_year year; this-_month month; this-_day day; } // 调用时 d1.Init(2022, 1, 11); // 被编译器转换为 Init(d1, 2022, 1, 11); // 传递d1的地址作为第一个参数显式使用this指针虽然编译器自动处理但我们也可以显式使用class Date { public: void Init(int year, int month, int day) { this-_year year; // 显式使用this this-_month month; this-_day day; } // 更常见的用途解决命名冲突 void SetDate(int _year, int _month, int _day) { this-_year _year; // this-_year是成员变量 this-_month _month; // _month是参数 this-_day _day; } // 返回对象自身的引用支持链式调用 Date addYear(int years) { this-_year years; return *this; // 返回当前对象 } Date addMonth(int months) { this-_month months; return *this; } private: int _year, _month, _day; }; // 链式调用 Date d; d.addYear(1).addMonth(2); // 连续操作三、this指针的特性1. 类型和不可变性class MyClass { public: void example() { // this的类型是MyClass* const // 意味着this本身是常量指针不能修改this指向别的地址 // this nullptr; // 错误不能修改this指针本身 } };2. 作用域限制class MyClass { public: void memberFunction() { cout this endl; // 正确在成员函数内使用 } private: // int* ptr this; // 错误不能在类定义中直接使用 }; void externalFunction() { // cout this endl; // 错误不能在非成员函数中使用 }3. 存储位置和传递方式// this指针是函数的形参不是对象的一部分 class Empty { // 空类没有成员变量 }; void demo() { Empty e; // e对象中不包含this指针 // this指针在调用成员函数时通过寄存器(如ecx)传递 }四、关键问题解析问题1this指针存在哪里答案this指针是成员函数的形参存在于函数调用的栈帧中或者通过寄存器传递。class Test { public: void func() { /* 这个函数实际是void func(Test* this) */ } }; // 调用时 Test obj; obj.func(); // 实际传递func(obj)可以理解为this指针并不存在对象中只有在调用时他才会作为形参出现存在栈帧中的特定位置调用结束又随着函数栈帧销毁消除了问题2this指针可以为空吗案例1正常运行class A { public: void Print() { cout Print() endl; // 没有访问成员变量 } private: int _a; }; int main() { A* p nullptr; p-Print(); // 正常运行 return 0; }分析没有访问成员变量不涉及this解引用所以安全。案例2运行崩溃class A { public: void PrintA() { cout _a endl; // 访问成员变量 ⇐ 这里会崩溃 } private: int _a; }; int main() { A* p nullptr; p-PrintA(); // 运行崩溃 return 0; }分析访问_a相当于this-_a而this是nullptr解引用空指针导致崩溃。重要结论this指针可以为空但只要不通过空this指针访问成员变量/虚函数程序就不会崩溃这是一种未定义行为要避免感谢你能够阅读到这里如果本篇文章对你有帮助欢迎点赞收藏支持关注我 我将更新更多有关CLinux系统·网络部分的知识。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

做网站需要监事吗制作人物的软件

ComfyUI-Impact-Pack工作流异常终极修复指南 【免费下载链接】ComfyUI-Impact-Pack 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-Impact-Pack 引言:问题背景与用户困扰 近期,众多ComfyUI用户在使用Impact-Pack扩展时遭遇了令人困扰的…

张小明 2026/1/1 18:04:17 网站建设

asp网站可运行jsp吗php网站开发岗位要求

8 个 MBA 文献综述工具,AI 写作降重推荐 论文写作的困境:MBA 学子的无声呐喊 MBA 学员在撰写论文的过程中,常常面临着前所未有的挑战。文献综述作为论文的重要组成部分,不仅需要大量的资料收集和整理,还要对已有研究进…

张小明 2026/1/1 18:04:16 网站建设

哈尔滨微网站建设公司seo是什么职位的缩写

Langchain-Chatchat问答系统灰度期间服务限流策略 在企业逐步将大模型技术引入内部知识管理系统的当下,一个现实问题始终萦绕在架构师心头:如何在不牺牲数据安全的前提下,让AI服务稳定可用?尤其是当Langchain-Chatchat这类本地化R…

张小明 2026/1/1 18:04:16 网站建设

浙江省建设厅门户网站做平台的网站有哪些

Bypass Paywalls Clean:突破内容付费墙的完整指南 【免费下载链接】bypass-paywalls-chrome-clean 项目地址: https://gitcode.com/GitHub_Trending/by/bypass-paywalls-chrome-clean 在当今数字信息时代,优质内容往往被付费墙所限制&#xff0c…

张小明 2026/1/1 18:04:17 网站建设

怎么样做网站代实体店怎么引流推广

在讨论 HTTPS DDoS 之前,很多人第一反应是防火墙、CDN 或云厂商的防护策略。但在真实项目中,开发者和运维往往最先面对的并不是“怎么防”,而是这到底是不是攻击,攻击长什么样。 而要回答这些问题,抓包几乎是绕不开的一…

张小明 2026/1/1 18:04:18 网站建设

沈阳网站建设方案外包网站维护的协议

大家好,我是玄姐。▼ 《双12 AI 原生应用落地专场》直播预约保你有收获当我询问 ChatGPT 关于我的记忆时,它列出了 33 个事实,从我的名字、职业目标到当前的健身计划应有尽有。但它究竟是如何存储和检索这些信息的?为何整个过程会…

张小明 2026/1/3 5:10:28 网站建设