C++程序设计第7章类和对象的基础_第1页
C++程序设计第7章类和对象的基础_第2页
C++程序设计第7章类和对象的基础_第3页
C++程序设计第7章类和对象的基础_第4页
C++程序设计第7章类和对象的基础_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

CHAPTER07C++程序设计第7章类和对象的基础从面向过程到面向对象——类域、实例化、this指针与内存模型Contents本章目录C++程序设计·第7章类和对象的基础01面向对象编程概述02类的定义与类域机制03对象的实例化与内存模型04this指针原理与应用05实战案例:Stack类完整实现CHAPTER01面向对象编程概述从C语言的面向过程到C++的面向对象,理解编程范式的根本转变ProgrammingParadigms·编程范式面向过程vs面向对象面向过程编程以函数为核心、数据与操作分离,适合小型程序但难以应对复杂系统;面向对象编程将数据和操作封装为类,通过封装、继承、多态三大特性实现代码的高内聚低耦合,是现代大型软件工程的基石。面向过程编程C·Procedural以函数为基本单元,程序被拆解为一系列有序的步骤和流程,数据通过参数在函数间传递数据与操作数据的函数相互分离,全局变量容易被任意函数修改,导致维护困难和隐蔽Bug代码复用主要依赖函数库和头文件,缺乏对复杂数据关系的抽象能力,系统规模增大后耦合度急剧上升面向对象编程C++·Object-Oriented以类为基本单元,将数据(属性)和操作数据的方法(行为)封装在一起,模拟现实世界的事物关系通过封装机制隐藏内部实现细节,外部只能通过公开接口访问,有效保护数据完整性和安全性支持继承和多态,允许在已有类的基础上扩展新功能,实现代码的高效复用和灵活扩展OOPFundamentals面向对象三大特性封装、继承、多态分别解决数据保护、代码复用和接口灵活性问题,三者协同构建高内聚低耦合架构。封装Encapsulation将数据成员和成员函数捆绑在类内部,对外只暴露必要的公开接口,隐藏具体实现细节通过public、private、protected三种访问限定符控制成员可见性,防止外部随意篡改类比:ATM机封装了账户操作逻辑,用户无需了解后台数据库如何运作数据保护继承Inheritance允许派生类在基类基础上创建,自动获得基类属性和方法并可扩展新功能支持单继承和多继承,通过层次化类体系实现代码纵向复用,减少重复编写类比:"汽车"派生出"电动汽车"和"燃油汽车",共享轮胎方向盘,各有特有动力系统代码复用多态Polymorphism同一接口在不同对象上表现出不同行为,提高代码的灵活性和可扩展性C++通过虚函数(virtual)和函数重载(overload)实现运行时多态和编译时多态类比:同样是"启动"指令,燃油车需点火,电动车按启动键即可,调用者无需关心实现接口灵活Chapter07·类和对象现实世界的类与对象类是对一类事物的抽象描述(蓝图),对象是该抽象的具体实例(实体)。汽车生产线——从蓝图到实体的实例化过程Class类=设计图纸:定义汽车应有的属性(品牌、型号、年份)和行为(启动、加速、刹车),是抽象模板,不占用物理内存Object对象=造出的实体:根据图纸生产的具体汽车,如一辆2024款丰田卡罗拉,每个对象独立占用内存存储各自的属性值1:N一对多关系:一份图纸(类)可生产无数辆汽车(对象),每辆车有独立数据,但共享同一套行为逻辑(成员函数)C++class.语法映射:用class关键字定义类,通过类名+变量名创建对象,用点操作符.访问属性和方法CHAPTER02类的定义与类域机制掌握class关键字、访问限定符、声明与定义分离等核心语法要素OOP·Chapter07类的基本定义语法C++使用class关键字定义类,类体中包含成员变量和成员函数,类定义本身不分配内存,仅作为对象实例化的蓝图。01class关键字+类名+花括号+分号构成完整的类定义,例如classStudent{...};—分号不可省略,否则编译器会报语法错误class...;02成员变量(数据成员)声明在类体内,描述对象的属性状态,如stringname;intage;—在对象实例化时才分配实际内存DataMembers03成员函数定义对象的行为能力,可在类体内实现(内联),也可在类体内声明、类体外定义(分离式),后者更适合复杂逻辑MemberFunc04类定义本身不占内存,它只是告诉编译器"这个类型长什么样",类似int类型定义本身不占内存,只有inta才会分配4字节0BytesENCAPSULATION访问限定符与封装C++通过public、private、protected三种访问限定符实现封装,控制类成员的可见性边界。class默认访问权限为private(与struct的public不同),遵循"数据私有、接口公开"的封装原则,是保护数据完整性的核心机制。三种访问限定符对比访问限定符类内部类外部派生类典型用途public✓✓✓对外接口函数,如构造、析构、getter/setterprivate✓✗✗内部数据成员,防止外部直接修改protected✓✗✓需要被子类继承但不对外的成员public对外开放、private对内封闭、protected为继承预留,三者组合实现精细化的封装控制Scope&Namespace类域与作用域解析类域是由类定义引入的独立作用域,类中所有成员都在类域内有效。类域影响编译器的名称查找规则,在类外定义成员函数时必须用::作用域限定符指明所属类域。Definition类域由class定义自动引入,类体内声明的成员变量和成员函数均处于该类域中,仅在类范围内有效。Operator类外定义成员函数时必须使用::作用域限定符(如Stack::Init),否则编译器将其视为全局函数,导致编译报错。Independence类域与全局作用域相互独立,类内成员名不会与全局变量冲突;类域与局部作用域也各自独立,函数内局部变量不会干扰类成员。Namespace命名空间域(namespace)是更灵活的全局域组织方式,与类域没有直接包含关系,但类可以定义在命名空间内形成嵌套作用域。C++·类和对象成员函数的定义方式C++成员函数支持类内定义(隐式内联)和类外定义(声明与定义分离)两种方式。工程实践中通常将类定义放入头文件(.h),将函数实现放入源文件(.cpp),既保持类定义简洁,又利于编译管理和团队协作。Inline类内定义函数体直接写在类体内,编译器默认将其视为内联函数,减少函数调用开销,适合简短的getter/setter等逻辑。//示例classPoint{intgetX(){returnx;}voidsetX(intv){x=v;}};Trade-off优点是实现紧凑、一目了然;缺点是类体过长时可读性下降,且每次修改函数实现都需要重新编译所有包含该头文件的源文件。Separation类外定义::类体内仅保留函数声明,实现写在类体外并使用::限定符,保持类定义简洁清晰。//示例classPoint{intgetX();};intPoint::getX(){returnx;}BestPractice将类声明放在头文件(.h)、函数实现放在源文件(.cpp),便于多人协作、缩短增量编译时间,是大型项目的标准做法。CHAPTER03对象的实例化与内存模型理解对象创建过程、内存分配机制与sizeof计算规则Chapter07·Classes&Objects对象的创建与使用对象通过类名+变量名的语法在栈上实例化,或用new在堆上动态创建。每个对象拥有独立的成员变量副本但共享成员函数代码。01栈上实例化CarmyCar;直接在栈区分配内存,对象生命周期随作用域结束自动回收,语法简洁但大小受限于栈空间。CarmyCar;02堆上实例化Car*pCar=newCar();在堆区动态分配内存,需手动delete释放,适合大型对象或需要灵活控制生命周期的场景。newCar()03成员访问栈对象用点操作符(myCar.brand),指针用箭头操作符(pCar→brand),二者等价,箭头是(*pCar).brand的简写。.&→04独立数据共享逻辑每个对象拥有独立的成员变量副本,但所有对象共享同一份成员函数的机器指令,成员函数不占对象内存。SharedCodeOBJECTSIZE对象大小的计算规则对象大小仅由成员变量决定,成员函数不占空间;实际大小受内存对齐影响,空类为1字节sizeof运算符计算对象所占内存字节数,如sizeof(Car)返回实际大小,结果在编译期即可确定编译期成员函数不占空间同类型对象共享同一份函数机器码,存储在代码段,函数多少不影响对象大小代码段内存对齐影响编译器为CPU访问效率进行对齐填充,如int(4B)+char(1B)实际占8B而非5B5B→8B空类大小为1无成员变量的空类sizeof为1而非0,保证每个对象拥有唯一内存地址1ByteMemoryAlignment内存对齐详解内存对齐是编译器为提升CPU访问效率而在成员变量间插入填充字节的机制。01第一个成员偏移量为0,后续每个成员的起始地址必须是min(自身大小,编译器默认对齐数)的整数倍02类/结构体的总大小必须是所有成员中最大对齐数的整数倍,不足则在末尾填充03#pragmapack(n)可修改默认对齐数,如#pragmapack(1)取消填充,常用于网络传输与文件存储计算示例·4字节对齐classExample{chara;intb;charc;}a1B+填充3B→b4B→c1B+填充3B调整声明顺序:chara,c相邻a,c2B+填充2B→b4B原始12B优化后8BCHAPTER04this指针原理与应用揭示成员函数如何定位调用对象的底层机制,理解隐式this参数的传递过程C++·类和对象this指针的引入动机非静态成员函数被所有对象共享,编译器通过隐式传递this指针来区分不同对象的数据操作。01核心问题成员函数代码只有一份,被所有对象共享,但d1.print()和d2.print()需要输出不同数据——函数如何区分调用者?02编译器方案在非静态成员函数的参数列表中隐式添加this指针参数,类型为类名*const,指向当前调用该函数的对象。03调用转换d1.print()被编译器转换为print(&d1),d2.print()转换为print(&d2),this指针分别指向不同对象的起始地址。04函数内访问成员函数中写year实际上是this->year的简写,通过this指针解引用访问调用对象对应的成员变量。C++·第7章类和对象this指针this指针是编译器隐式传递的常量指针(类名*const),仅存在于非静态成员函数中,由编译器自动管理,程序员无需手动传递。this指针的性质常量指针类型为类名*const,指针本身不可修改,不能指向其他对象,但可通过指针修改所指向对象的成员数据。隐式传递由编译器在调用时自动压栈传递,程序员不需要也不能手动传递,函数签名中不可见但确实存在。非静态专属仅存在于非静态成员函数中;静态成员函数没有this指针,因为static函数属于类而非某个特定对象。常见使用场景解决命名冲突构造函数中this->name=name;区分同名的形参和成员变量,是C++中最常见的this用法。Person(stringname){this->name=name;}链式调用成员函数返回*this引用,如obj.set(20).setName("Tom"),实现流式API风格。Person&setAge(inta){age=a;return*this;}Comparisonthis指针vsC语言结构体指针this指针的本质与C语言中手动传递结构体指针完全相同,都是为了让函数知道操作哪个对象的数据。C++将这一过程自动化——编译器隐式传递this指针,消除了手动传参的冗余和出错风险,是语法层面的优雅封装。对比维度C语言方式C++方式函数定义voidInit(Stack*ps,intn){ps->top=0;}voidStack::Init(intn){top=0;}函数调用Init(&st,10);—手动传递结构体地址st.Init(10);—编译器自动传递&st作为this成员访问ps->array,ps->capacity—显式通过指针array,capacity—隐式通过this,可省略this->安全性可能传NULL指针,需手动检查this指针由编译器保证非空(正常调用场景)C++的this指针是对C语言手动传结构体指针的自动化封装,底层原理一致,语法更简洁安全。C++·类和对象经典面试问题:this指针与安全空指针调用成员函数是否崩溃取决于函数是否解引用this指针访问成员数据。非静态成员函数访问成员变量时会解引用this,空指针导致崩溃;静态成员函数没有this指针,空指针调用不会崩溃。理解这一点需要深入掌握this指针的传递与使用机制。01空指针调用非静态函数Student*p=nullptr;p->print();print()this->nameStudent*p=nullptr;p->print();若print()内部访问了this->name等成员变量,解引用空指针导致程序崩溃(段错误)print()cout<<"hello"thisnullptr若print()内部仅执行cout<<"hello"而不访问任何成员,this虽为nullptr但未解引用,程序不会崩溃(但属于未定义行为)RISK段错误02空指针调用静态函数Student*p=nullptr;p->showCount();showCount()staticthisStudent*p=nullptr;p->showCount();若showCount()是static静态函数,不存在this指针,调用不依赖对象地址,不会崩溃thisStudent::showCount()p本质原因:静态函数属于类而非对象,编译器不传递this指针,等价于Student::showCount(),与p的值无关SAFE无thisCHAPTER05实战案例:Stack类完整实现从零构建一个动态栈类,综合运用类定义、封装、内存管理与this指针ClassDesignStack类设计规划Stack类遵循"数据私有、接口公开"的封装原则,将动态数组指针、容量和栈顶索引作为private成员保护内部状态,将初始化、入栈、出栈、查看栈顶、判空和销毁等操作作为public接口对外暴露,实现了高内聚低耦合的类设计。PRIVATE成员变量01int*array—指向动态分配的数组空间,用于存储栈中元素,需要手动malloc/free管理内存生命周期02size_tcapacity—记录当前数组的总容量,用于判断是否需要扩容,初始值由Init函数的参数决定03size_ttop—记录栈顶元素的下一个位置索引,top=0表示空栈,Push时top++,Pop时top--PUBLIC成员函数01Init(intn=4)—初始化栈,分配n个int大小的动态数组,设置capacity和top初始值02Push(intx)/Pop()—入栈和出栈操作,Push需检查是否满载,Pop需检查是否空栈03Top()/Empty()/Destroy()—查看栈顶元素、判断是否为空、释放动态内存并重置指针CHAPTER7·STACKIMPLEMENTATIONInit初始化函数实现Init函数负责为Stack对象分配动态数组空间并初始化状态变量。实现中必须进行malloc返回值检查以防止内存分配失败导致的空指针访问。01函数签名类外定义使用Stack::作用域限定符指明类域,默认参数n=4允许调用时不传参voidStack::Init(intn=4)02内存分配动态分配n个int大小的连续内存空间,array指针存储首地址malloc(sizeof(int)*n)03安全检查检查malloc返回值,失败时调用perror打印错误信息并提前returnnullptr==array04状态初始化通过隐式this指针访问成员变量,设置容量与栈顶索引初始值capacity=ntop=0STACKOPERATIONSPush入栈与Pop出栈实现Push操作将元素写入array[top]并递增top,需先检查栈是否满载;Pop操作递减top实现逻辑出栈,需先检查栈是否为空。Push入栈CORELOGICarray[top++]=x;将元素写入栈顶位置,top自增指向新空位SAFETYCHECK判断top==capacity,满栈需realloc扩容,否则越界破坏内存THISPOINTERd1.Push(5)时this=&d1,同一代码操作不同对象数据array[top++]=xPop出栈CORELOGICtop--;仅需栈顶索引减1,原位置数据下次Push自动覆盖SAFETYCHECK必须判断top==0,空栈Pop致top下溢为极大值引发严重错误DESIGN只改索引不删数据,时间复杂度O(1),体现栈操作高效简洁top--·O(1)StackLifecycleTop、Empty与Destroy实现Top函数返回array[top-1]获取栈顶元素,Empty通过top==0判断空栈状态,Destroy释放动态内存并重置指针防止悬空。三个函数构成了Stack类的完整生命周期管理,Destroy的内存清理职责在后续学习析构函数后将被自动化。Top获取栈顶returnarray[top-1];top指向栈顶下一位置,故top-1才是栈顶元素下标,调用前需确认栈非空(top>0)。array[top-1]Empty判空returntop==0;利用布尔表达式直接返回判断结果,空栈返回true,非空返回false,实现简洁高效。true/falseDestroy销毁free(array)释放动态数组内存;array=nullptr防止悬空指针;top=capacity=0重置状态,避免二次释放。nullptr资源管理意识Init分配内存与Destroy释放内存必须配对使用,遗漏Destroy将导致内存泄漏,这是C++手动内存管理的核心责任。配对使用STACK·生命周期Stack类完整使用流程从对象声明到Init初始化、Push/Pop操作再到Destroy释放,Stack类的完整使用流程演示了类的生命周期管理。每次成员函数调用都由编译器隐式传递this指针,确保操作作用于正确的对象实例,多对象场景下各对象数据完全独立。01声明对象Stackst;编译器为st分配sizeof(Stack)字节栈空间,包含array指针(8B)、capacity(8B)、top(8B)共24字节24字节02初始化st.Init();调用Init函数,this指针自动指向st,为st的array成员分配动态内存,capacity=4,top=0capacity=403入栈操作st.Push(1);st.Push(2);st.Push(3);三次调用Push,依次将1、2、3写入array,top从0递增到3Push×304出栈与销毁st.Pop();top从3减为2,逻辑删除栈顶元素3;st.Destroy();释放array指向的堆内存,完成资源回收DestroyCHAPTER07·SUMMARY本章知识点总结第7章系统讲解了C++类与对象的基础知识,从面向对象编程的宏观思想到类定义、对象实例化、this指针的微观机制,构建了完整的认知框架。这些知识是后续学习构造/析构函数、运算符重载、继承与多态的必要基础。SECTION01核心概念01类是抽象蓝图(不占内存),对象是具体实例(占内存);封装、继承、多态是面向对象三大特性02class定义语法包含成员变量和成员函数,访问限定符(public/private/protected)实现封装控制封装·继承·多态SECTION02底层机制01类域是独立作用域,类外定义成员函数必须用::限定符;内存对齐影响对象实际大小,空类大小为1字节02this指针是编译器隐式传递的常量指针(类名*const),仅存在于非静态成员函数中,用于区分不同调用对象::作用域·this指针SECTION03下章预告第8章将学习构造函数与析构函数,实现对象创建时的自动初始化和

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论