还剩48页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
类和对象欢迎来到《类和对象》课程在这门课程中,我们将深入探讨面向对象编程的核心概念——类与对象通过学习这些基础概念,您将能够掌握C++面向对象编程的精髓,为构建复杂且高效的软件系统打下坚实基础面向对象编程是现代软件开发中不可或缺的一部分,而类和对象则是其中最基本的构建块本课程将帮助您理解如何定义类、创建对象,以及如何利用面向对象的特性如封装、继承和多态来解决实际问题课程目标掌握面向对象基础概念1通过本课程,学生将深入理解面向对象编程的核心理念,包括类、对象、封装、继承和多态等基本概念,为后续高级编程打下坚实基础学会类的设计与实现2学生将学习如何正确设计类结构,定义成员变量和成员函数,掌握访问修饰符的使用,以及如何实现类的封装性,提高代码的安全性和可维护性掌握类的高级特性应用3学习构造函数、析构函数、运算符重载等高级特性,并理解如何在实际编程中应用这些特性解决复杂问题,提升代码质量和效率培养面向对象思维能力4培养学生用面向对象的思维分析问题、设计解决方案的能力,能够将现实世界的实体抽象为类和对象,提高软件设计的直观性和可重用性面向对象编程简介概念定义三大特性与过程式编程的区别面向对象编程(OOP)是一种编程范面向对象编程的三大特性是封装、继面向对象编程通过创建模块化的对象式,它使用对象这一概念来组织代承和多态封装隐藏内部细节,继承来组织代码,而过程式编程通过线性码对象包含数据和操作数据的方法,实现代码重用,多态允许不同类的对顺序的功能模块执行任务OOP更适这与现实世界中实体的特性和行为相象对相同消息作出不同响应合大型、复杂的系统开发对应类的定义类的本质类与对象的关系类是用户定义的数据类型,是类与对象的关系类似于模具与对象的模板或蓝图它描述了产品类是抽象的模板,定义一组具有相同属性(数据元素)了类型的特性;而对象是类的和行为(函数)的对象类定具体实例,占用实际内存空间,义了对象的特征和行为方式,具有类定义的所有特性但不分配任何实际内存类的组成部分类通常由两部分组成数据成员(属性)和成员函数(方法)数据成员定义对象的状态,而成员函数定义对象能执行的操作类通过访问修饰符控制数据和方法的可见性类的基本语法类声明结束类体定义使用分号结束类的声明这一点很容易被忽声明关键字在大括号内定义类的成员变量和成员函数略,但缺少这个分号会导致编译错误完整使用class或struct关键字开始类的声明在可以按照访问修饰符(public、private、的类定义形式为class类名{成员列表};C++中,class默认成员为private,而struct protected)组织成员,明确指定哪些成员默认成员为public,其他方面完全相同可以被外部访问对象的创建静态创建对象使用类名直接声明对象,与声明基本数据类型变量类似ClassName objectName;这种方式创建的对象在栈内存中分配,程序离开对象作用域时会自动销毁动态创建对象使用new关键字在堆内存中创建对象ClassName*pObject=new ClassName;这种方式创建的对象需要手动使用delete关键字释放内存,否则可能导致内存泄漏带参数创建对象如果类定义了带参数的构造函数,可以在创建对象时传递参数ClassNameobjectNameparam1,param2;或ClassName*pObject=new ClassNameparam1,param2;对象数组创建可以创建对象数组,静态方式ClassName objectArray[size];,动态方式ClassName*pObjectArray=new ClassName[size];成员变量定义与特点访问控制成员变量是类中用于存储数据的变成员变量可以通过访问修饰符量,代表对象的属性或状态它们1(public、private、protected)控定义在类的内部,但不在任何成员2制其可见性通常将成员变量设为函数内部private,通过public方法访问内存分配初始化方式非静态成员变量属于对象的一部分,成员变量可以在声明时初始化4每个对象都有自己独立的成员变量(C++11以后),也可以在构造函数3副本静态成员变量则由该类的所中初始化,或者通过初始化列表进有对象共享行初始化成员函数定义方式1成员函数可以在类内直接定义,也可以在类外通过作用域解析运算符(::)定义在类内定义的函数通常会被编译器视为内联函数,而在类外定义的则需要在类内声明访问成员2成员函数可以直接访问类中的所有成员变量和其他成员函数,无需通过对象名或指针这是因为每个成员函数都隐含地接收到一个指向调用该函数的对象的this指针类型分类3成员函数可分为普通成员函数、构造函数、析构函数、静态成员函数和常成员函数等普通成员函数实现对象的行为,而特殊成员函数如构造和析构函数则负责对象的生命周期管理访问修饰符、、public privateprotectedpublic可在类外部访问1protected2仅限本类和子类访问private3仅限本类内部访问访问修饰符是面向对象编程中实现封装的重要机制,它们控制类的成员变量和成员函数的可见性和访问权限C++提供了三种访问修饰符private、protected和publicprivate成员只能在类的内部访问,外部无法直接访问,这是最严格的访问级别;protected成员可以在类内部和派生类中访问,但在类外部不能直接访问;public成员可以在任何地方访问,没有限制默认情况下,class的成员是private的,而struct的成员是public的合理使用访问修饰符可以提高代码的安全性、降低模块间的耦合度,并防止类的使用者误用类的内部实现细节封装的概念信息隐藏接口提供模块化封装通过访问修饰符封装为类提供了公共封装使类成为独立的隐藏类的内部实现细接口(成员函数),模块,内部变化不会节,使外部代码无法外部代码通过这些接对外部系统造成影响直接访问和修改类的口与类交互这些公这种模块化设计使代内部数据这种隐藏共接口保持稳定,即码更易于测试、维护保护了数据的完整性,使内部实现发生变化,和理解,大大提高了防止无意的修改也不会影响使用该类软件开发的效率的代码构造函数介绍基本概念1构造函数是一种特殊的成员函数,当创建类的新对象时自动调用它与类同名,不返回任何值,也不需要指定返回类型,甚至不用void构造函数主要用于初始化对象的成员变量和分配资源构造函数类型2C++中的构造函数分为几种类型默认构造函数(无参)、带参数的构造函数、拷贝构造函数、移动构造函数(C++11)一个类可以有多个构造函数,通过函数重载区分,编译器根据参数类型和数量决定调用哪个初始化列表3构造函数可以使用初始化列表语法来初始化成员变量,格式为构造函数参数:成员1值1,成员2值2{}这种方式比在函数体内赋值更高效,对于常量成员和引用成员是必需的默认构造函数定义特点合成规则默认构造函数是不带参数的构造如果一个类没有定义任何构造函函数,或者所有参数都有默认值数,编译器会自动生成一个隐式的构造函数当创建对象而不提的默认构造函数这个隐式构造供初始化参数时,编译器会调用函数没有执行任何初始化操作默认构造函数默认构造函数通但是,一旦你定义了任何其他构常负责将对象的成员变量初始化造函数,编译器就不会再生成默为合理的默认值认构造函数关键字=default在C++11及以后的版本中,可以使用=default关键字显式地请求编译器生成默认构造函数,格式为ClassName=default;这在你已经定义了其他构造函数,但仍然希望保留默认构造函数时很有用带参数的构造函数基本形式带参数的构造函数允许在创建对象时传入特定的初始值,使对象创建后就具有预期的状态它的声明形式为ClassNameparameter_list;,定义形式为ClassName::ClassNameparameter_list{//初始化逻辑}参数处理构造函数的参数可以是任意类型,包括基本类型、类对象、指针或引用参数可以有默认值,当创建对象时未提供该参数,则使用默认值如果所有参数都有默认值,这个构造函数也可以作为默认构造函数初始化列表在带参数的构造函数中,推荐使用成员初始化列表来初始化成员变量,而不是在函数体内赋值初始化列表语法为ClassNameparams:member1value1,member2value2{}这种方式效率更高,特别是对于类类型成员拷贝构造函数自定义实现隐式调用情况如果类管理动态分配的资源,必须自定义拷贝基本定义拷贝构造函数在多种情况下被隐式调用1)通构造函数实现深拷贝,避免多个对象共享同一拷贝构造函数是一种特殊的构造函数,用于创过现有对象初始化新对象;2)函数按值传递对资源导致的问题默认的拷贝构造函数只进行建一个对象的副本它接受一个同类型对象的象参数;3)函数返回对象(某些优化情况除浅拷贝,简单复制所有成员变量的值常量引用作为参数,格式为外)理解这些情况有助于编写高效的代码ClassNameconst ClassNameother;当通过另一个对象初始化新对象时,会自动调用拷贝构造函数析构函数基本概念调用时机自定义实现析构函数是一种特殊的成员函数,在析构函数在以下情况被调用1)栈中如果类没有管理特殊资源,可以使用对象被销毁时自动调用它的名称由的对象离开其作用域;2)堆中的对象编译器生成的默认析构函数但如果波浪号~加类名组成,没有返回值和通过delete操作符删除;3)临时对象类管理动态分配的内存或其他资源参数,如~ClassName析构函数在表达式结束时;4)程序结束时,全(如文件、网络连接),必须自定义负责释放对象占用的资源,执行必要局或静态对象被销毁析构函数调用析构函数释放这些资源,否则会导致的清理工作,防止资源泄漏顺序与构造函数相反资源泄漏指针this基本概念常见用途this指针是一个隐含的参数,指向调用成员函数的对象this指针有多种常见用途1)区分同名的成员变量和局部每个非静态成员函数都有this指针,指向调用该函数的对变量,如this-data=data;2)在成员函数中返回当前对象this指针本质上是一个常量指针,不能被修改象的引用,实现链式调用,如return*this;3)将当前对象作为参数传递给其他函数通过this指针,成员函数可以访问调用它的对象的所有成员变量和成员函数,即使这些成员与局部变量同名在实现运算符重载时,this指针尤其有用,可以实现如obj1+obj2这样的表达式静态成员变量基本特性1静态成员变量是属于类而不是对象的变量,无论创建多少个对象,静态成员变量只有一份拷贝,被该类的所有对象共享静态成员变量存在于全局数据区,而不是对象内部,因此不影响对象的大小声明与定义2静态成员变量在类内部通过static关键字声明,但必须在类外部进行定义和初始化例如在类内声明static intcount;,在类外定义int ClassName::count=0;const静态成员可以在类内初始化访问方式3静态成员变量可以通过类名直接访问ClassName::staticVar,也可以通过对象访问obj.staticVar推荐使用类名访问,更清楚地表明这是一个静态成员静态成员遵循类访问规则,如果是private,外部不能访问典型应用4静态成员变量常用于1)记录类的实例数量;2)维护所有对象共享的数据;3)实现单例模式;4)作为类的常量配置;5)代替全局变量,提供作用域限制,避免命名冲突静态成员函数使用限制静态成员函数只能访问静态成员变量和其他静态成员函数,不能使用this指针,也不能被声明为const、volatile或虚函2基本特点数它们主要操作类的静态数据成员或执行不依赖特定对象的函数静态成员函数是属于类而不是对象的函数,可以通过类名直接调用,无需常见应用1创建对象它们使用static关键字在类内声明,不含this指针,因此不能访问静态成员函数常用于1)操作静态成员非静态成员变量和成员函数变量;2)创建实例(工厂方法);3)3实现单例模式;4)提供不依赖对象状态的实用函数;5)组织相关功能为逻辑组,比全局函数有更好的封装性成员函数const基本定义1const成员函数是指不会修改任何非静态成员变量的函数,通过在函数声明和定义中的参数列表后加const关键字来定义例如void display const;const成员函数不能修改对象的状态,确保对象在函数调用前后保持不变使用规则2const成员函数有严格的限制不能修改任何非静态成员变量;不能调用非const成员函数;可以访问但不能修改非静态成员变量;可以自由访问和修改静态成员变量(因为静态成员不属于特定对象)关键字mutable3如果在const成员函数中确实需要修改某些特定成员变量,可以将这些变量声明为mutablemutable关键字告诉编译器,即使在const成员函数中,这个变量也可以被修改,通常用于缓存或锁等不影响对象逻辑状态的成员友元函数基本概念声明方式使用场景友元函数是一种特殊友元函数通过在类内友元函数主要用于需的非成员函数,它被部使用friend关键字要同时访问多个类内授予访问类的私有和声明,但函数定义在部细节的情况,例如保护成员的权限友类外部声明格式实现两个类对象间的元函数不是类的成员,friend返回类型函数转换或比较;重载运因此不能使用this指名参数列表;友元算符以提供更自然的针,但它可以像成员函数的声明可以出现语法;需要访问类私函数一样访问类的所在类的任何部分有成员但逻辑上不属有成员(public、private或于类的功能protected),不受访问修饰符影响友元类基本概念声明方式友元类是一种特殊的类,它被授予通过在主类内部使用friend关键字加访问另一个类(称为主类)的私有类名来声明友元类,格式为friend和保护成员的权限友元类的所有class FriendClassName;友元类的成员函数都可以访问主类的所有成声明可以出现在主类的任何部分员,包括私有和保护成员友元关(public、private或protected),系是单向的,A类声明B为友元,并位置不影响友元关系,只是为了代不意味着B类也能将A类声明为友元码可读性通常放在类的开始或结束部分使用注意友元类打破了类的封装性,降低了代码的模块化和可维护性,应谨慎使用友元关系不具有传递性,即如果A是B的友元,B是C的友元,A不自动成为C的友元友元类不能被继承,如果D继承自A,D不自动成为B的友元内联函数基本原理适用场景使用限制内联函数是一种性能优化技术,通过内联函数适合于简短、频繁调用的函内联函数的定义通常需要放在头文件在调用点展开函数体代码,消除函数数,如访问器和修改器中,确保在每个调用点都能获得函数调用开销使用inline关键字或在类(getter/setter)复杂函数内联可定义递归函数、包含静态变量、循定义内部直接定义函数来声明内联函能导致代码膨胀,反而降低性能循环、switch、goto的复杂函数可能不数内联只是对编译器的建议,最终环中调用的简单函数是内联的好候选会被内联过度使用内联可能增加可是否内联由编译器决定者,可以显著减少函数调用开销执行文件大小,影响指令缓存效率对象数组基本定义对象数组是由同一类型的多个对象组成的数组每个数组元素都是一个完整的对象,具有类定义的所有成员变量和成员函数对象数组可以像基本类型数组一样声明和使用,但初始化和操作有特殊要求创建方式静态创建ClassName objectArray[size];动态创建ClassName*pObjectArray=new ClassName[size];,需要用delete[]pObjectArray释放创建时,每个对象都会调用相应的构造函数;销毁时,每个对象都会调用析构函数初始化方式如果类有默认构造函数,可以简单声明数组而不显式初始化;如果需要使用带参数的构造函数,可以使用初始化列表(C++11前后语法不同);也可以创建后逐个初始化数组元素,如对动态数组objectArray[i]=ClassNameargs对象指针基本概念对象指针是指向类对象的指针,存储对象的内存地址通过对象指针可以访问对象的成员对象指针声明格式为ClassName*pObject;,必须在使用前指向有效对象,可以是栈对象或堆对象创建与初始化创建对象指针ClassName*pObject;指向已有栈对象ClassNameobj;ClassName*pObject=obj;创建动态对象ClassName*pObject=new ClassName;,使用完需调用delete pObject释放内存成员访问通过对象指针访问成员使用箭头操作符(-)pObject-memberVariable或pObject-memberFunction这与通过对象直接访问(使用点操作符.)的区别在于对象指针指向的是对象的内存地址,需要先解引用再访问成员对象引用基本概念参数传递返回引用对象引用是对象的别对象引用最常用于函函数可以返回对象引名,提供了一种不使数参数,可以避免对用,常用于操作符重用指针就能间接访问象拷贝的开销通常载和链式调用对象的方式引用必使用const引用作为函ClassName须在创建时初始化,数参数void operator=const并且一旦绑定到一个funcconst ClassNameother;对象,就不能再引用ClassName obj;,这返回引用必须确保引其他对象对象引用既避免了拷贝,又防用的对象在函数返回的声明格式为止函数修改原对象后仍然有效,不要返ClassName非const引用参数允许回局部变量的引用,refObject=函数修改原对象,常会导致悬垂引用错误someObject;用于需要输出多个结果的场景类的组合基本概念实现方式12类的组合(也称为构成或聚合)是指在一个类中包含其他类的对象作在类定义中,直接将其他类的对象声明为成员变量class Car为成员变量组合实现了has-a关系,例如,Car类可能包含Engine对{private:Engine engine;Wheel wheels
[4];...};组合的对象可以是公象、Wheel对象等组合是一种常用的代码重用机制,允许通过组装已有、私有或保护成员,访问权限取决于设计需求组合类的方法可以有类来构建更复杂的类调用被组合对象的公有方法来实现功能初始化顺序与继承的对比34组合类的构造函数需要初始化其包含的成员对象初始化顺序是先组合与继承都是代码重用机制,但用途不同组合表示has-a关系,按声明顺序初始化成员对象,再执行构造函数体可以在构造函数的继承表示is-a关系组合更灵活,耦合度低,可以在运行时改变关系;初始化列表中为成员对象提供参数Carparams:继承耦合度高,子类与父类紧密绑定设计时应优先考虑组合而非继engineengineParams,wheels{wheelParams}{...}承,除非真正需要继承的特性运算符重载概念基本原理实现方式限制规则运算符重载允许为用户定义的类型重运算符重载有两种主要实现方式1)运算符重载有一些重要限制不能改新定义C++内置运算符的行为通过作为类的成员函数;2)作为全局函变运算符的优先级、结合性和操作数运算符重载,可以让自定义类型使用数(通常声明为友元)成员函数形数量;不能创建新运算符;某些运算如+、-、*、/等运算符,提高代码的式returnType operator运算符参符如.,.*,::,:,sizeof等不能可读性和直观性运算符重载本质上数;友元函数形式friend重载;只能重载已有的C++运算符;是函数重载的特殊形式,重载的运算returnType operator运算符参数1,重载的运算符必须至少有一个操作数符函数名为operator加运算符参数2选择哪种实现方式取决于运是用户定义类型算符的语义和参数转换需求重载一元运算符基本概念1一元运算符只有一个操作数,C++中常见的一元运算符包括正号+、负号-、自增++、自减--、逻辑非!等重载一元运算符允许这些运算符应用于自定义类型对象,使代码更加直观和易读成员函数方式2作为成员函数重载一元运算符时,不需要参数,因为操作数就是调用对象本身例如ReturnType operator-const;或ReturnType operator++;后置自增/自减需要一个int参数(仅作为标记,无实际用途)ReturnTypeoperator++int;全局函数方式3作为全局函数重载一元运算符时,需要一个参数表示操作数例如friendReturnType operator-const ClassName obj;全局函数重载形式通常用于左操作数不是该类对象的情况,或需要进行类型转换的场合重载二元运算符基本概念成员函数方式二元运算符有两个操作数,包括加作为成员函数重载二元运算符时,+、减-、乘*、除/、赋值=等左操作数是调用对象,右操作数作重载二元运算符使自定义类型能够1为参数传入例如ReturnType支持这些运算,提高代码的自然性2operator+const ClassNameother和可读性const;选择方式全局函数方式当左操作数是类的对象时,两种方作为全局函数重载二元运算符时,4式都可以;当左操作数不是类对象两个操作数都作为参数传入例如3时(如int+obj),只能用全局函数friend ReturnTypeoperator+const方式全局函数通常声明为友元以ClassName lhs,const访问私有成员ClassName rhs;重载赋值运算符基本概念赋值运算符=是一种特殊的二元运算符,用于将一个对象的值赋给另一个对象默认的赋值运算符执行成员变1量的浅拷贝,对于管理动态资源的类,需要重载赋值运算符实现深拷贝实现要点赋值运算符必须作为成员函数重载;返回类型通常是对象的引用ClassName,实现2链式赋值;参数通常是const引用;必须处理自赋值情况;应释放目标对象已有资源再分配新资源标准形式标准形式为ClassName operator=const ClassNameother3{ifthis!=other{//释放资源//分配新资源//复制数据}return*this;}重载流运算符基本概念输出流运算符流运算符包括输出流运算符和输输出流运算符通常定义为全局友入流运算符,重载这些运算符可元函数,返回ostream的引用以支持以让自定义类型对象直接与C++标准链式操作标准形式为friend输入输出流交互重载流运算符使ostream operatorostreamos,得对象的输入输出操作更加简洁直const ClassNameobj{os对象观,如coutobj;或cinobj;内容;return os;}该函数通常不修改对象,因此参数使用const引用输入流运算符输入流运算符也定义为全局友元函数,返回istream的引用标准形式friend istreamoperatoristream is,ClassNameobj{is对象成员;return is;}该函数需要修改对象,因此参数不使用const应考虑输入验证和错误处理继承的基本概念多态子类对象按父类接口使用1继承2派生类获得基类特性封装3数据与方法的绑定继承是面向对象编程的三大特性之一,允许创建从现有类派生的新类基类(或父类)提供一组属性和方法,派生类(或子类)继承这些特性并可以添加自己的新特性或修改继承的行为继承体现了是一个(is-a)的关系,表示派生类是一种特殊的基类例如,猫是一种动物,所以猫类可以继承动物类通过继承,可以实现代码的重用,减少重复代码,构建类层次结构,并为多态性提供基础C++支持多种继承方式公有继承(public)、保护继承(protected)和私有继承(private),它们影响基类成员在派生类中的访问权限最常用的是公有继承,保持基类成员在派生类中的原始访问性质单继承基本语法单继承是指一个派生类只从一个基类继承语法格式为class DerivedClass:[access-specifier]BaseClass{...};,其中access-specifier可以是public、protected或private最常用的是public继承,如class Cat:public Animal{...};访问规则在公有继承中,基类的public成员在派生类中仍为public,protected成员仍为protected;在保护继承中,基类的public和protected成员在派生类中都变为protected;在私有继承中,基类的public和protected成员在派生类中都变为private构造与析构派生类对象的构造过程先调用基类构造函数,再执行派生类构造函数;析构过程则相反,先执行派生类析构函数,再调用基类析构函数派生类构造函数可以通过初始化列表调用特定的基类构造函数DerivedClass:BaseClassargs{...}成员访问派生类可以直接访问基类的public和protected成员,但不能访问private成员如果派生类中的成员与基类同名,会隐藏基类成员可以使用作用域解析运算符::访问被隐藏的基类成员BaseClass::memberName多继承基本概念菱形继承问题成员访问与冲突多继承是指一个派生类从多个基类同时继承多继承可能导致菱形继承问题如果类D如果多个基类包含同名成员,派生类访问该语法格式为class DerivedClass:[access-继承自类B和类C,而B和C都继承自类A,成员时需要指定基类,避免歧义specifier1]BaseClass1,[access-specifier2]则D会包含A的两份副本这可能导致歧义BaseClass1::memberName或BaseClass2,...{...};例如class Bat:和资源浪费解决方法是使用虚拟继承BaseClass2::memberName如果派生类public Mammal,public WingedAnimal{...};(virtual inheritance)class B:virtual定义了与基类同名的成员,会隐藏所有基类多继承允许派生类组合多个基类的特性public A{...};class C:virtual publicA{...};的同名成员合理设计类层次结构和命名规范可以减少多继承带来的复杂性继承中的构造函数和析构函数构造顺序在继承层次中,对象构造的顺序是先构造基类对象,再构造派生类对象如果有多个基类(多继承),按照它们在派生类声明中的顺序构造派生类构造函数通过初始化列表调用特定的基类构造函数DerivedClassparams:BaseClassbaseParams{...}析构顺序对象析构的顺序与构造相反先执行派生类析构函数,再执行基类析构函数如果有多个基类,按与构造相反的顺序析构析构函数的调用是自动的,不需要在派生类析构函数中显式调用基类析构函数当基类析构函数为虚函数时,可以确保正确释放派生类对象的资源构造函数继承C++11引入了构造函数继承语法,允许派生类直接继承基类的构造函数,减少代码重复using BaseClass::BaseClass;这使派生类自动获得与基类相同的所有构造函数版本,但不包括复制和移动构造函数构造函数继承不会继承默认参数虚函数使用规则基本概念虚函数的声明只需在基类函数声明前加virtual关键字,派生类可以使用override关键字虚函数是在基类中使用virtual关键字声明的成员函数,允许在派生类中重写(覆盖)(C++11)标明重写的函数虚函数必须有定义,除非是纯虚函数派生类重写的函数虚函数实现了多态性,使得通过基类指针或引用调用成员函数时,实际执行的是对象必须与基类函数有完全相同的签名(返回类型、参数列表)和相同或更宽松的访问权真实类型对应的函数版本,而不是编译时静态绑定的版本限123实现机制虚函数通过虚函数表(vtable)实现包含虚函数的类对象会有一个指向虚函数表的指针(vptr)虚函数表是一个函数指针数组,存储该类所有虚函数的地址当派生类重写虚函数时,虚函数表中相应的函数指针会指向重写后的函数,实现动态绑定纯虚函数和抽象类纯虚函数1纯虚函数是一种特殊的虚函数,在基类中没有实现,只有声明,通过在函数声明后加=0表示virtual ReturnType functionNameparameters=0;纯虚函数表明派生类必须提供该函数的实现,否则也会成为抽象类纯虚函数可以有默认实现,但仍需在派生类中重写抽象类2包含至少一个纯虚函数的类称为抽象类抽象类不能被实例化,只能作为基类被继承抽象类的主要目的是定义接口,确保所有派生类都实现特定的功能抽象类可以包含普通成员变量和非虚函数,也可以提供纯虚函数的默认实现,供派生类调用接口类3接口类是一种特殊的抽象类,只包含纯虚函数,没有成员变量和函数实现接口类定义了一组功能,任何实现该接口的类都必须提供这些功能的实现C++没有专门的interface关键字,但可以使用只包含纯虚函数的抽象类实现接口概念设计模式应用4纯虚函数和抽象类广泛应用于设计模式中,如策略模式、工厂方法模式、观察者模式等它们提供了统一的接口,增强了代码的灵活性和可扩展性,使得可以在不修改现有代码的情况下添加新功能多态性定义与分类实现机制使用场景多态性是面向对象编程的三大特性之一,允许C++的运行时多态通过虚函数表和虚函数指针多态性在需要处理多种派生类对象的场景非常使用基类指针或引用调用派生类对象的成员函实现当类包含虚函数时,编译器会为该类创有用,如集合中存储不同类型的对象;工厂数,实际执行的函数版本取决于指针或引用所建一个虚函数表,存储虚函数的地址每个对方法创建派生类对象;回调函数执行不同的操指对象的实际类型C++支持两种多态编译象都有一个隐藏的指针,指向该类的虚函数表作;游戏中处理不同类型的角色多态性使代时多态(通过函数重载和运算符重载实现)和调用虚函数时,系统根据对象的实际类型找到码更灵活、可扩展,符合开闭原则对扩展运行时多态(通过虚函数实现)对应的虚函数表,再调用相应的函数开放,对修改关闭虚析构函数基本概念使用规则虚析构函数是在基类中使用virtual关键字声明的析构函数任何作为基类的类(尤其是多态类)都应该有虚析构函数,virtual~ClassName;当通过基类指针删除派生类对象即使析构函数没有实际工作要做如果类不是设计为基类,时,虚析构函数确保先调用派生类的析构函数,再调用基或者不会通过基类指针删除,则不需要虚析构函数类的析构函数,正确释放派生类的资源如果基类析构函数不是虚函数,通过基类指针删除派生类虚析构函数的声明与定义与普通虚函数相同,派生类不需对象时,只会调用基类的析构函数,导致派生类资源泄漏要使用virtual关键字(但可以使用,增加可读性)纯虚析构函数必须有定义,因为每个派生类的析构函数都会自动调用基类析构函数模板函数基本概念声明与定义模板函数是C++中实现泛型编程的方式,允许函模板函数声明格式template typenameT数操作不同类型的数据而无需为每种类型编写ReturnTypefunctionNameparameters;定独立的函数模板函数使用template关键字定义格式template typenameT ReturnType义,后跟尖括号中的类型参数列表,形式为1functionNameparameters{...}模板函数通template typenameT或template classT2常在头文件中定义,因为编译器需要在使用点看到完整定义生成具体版本类型推导模板特化调用模板函数时,可以显式指定类型当需要为特定类型提供不同的实现时,可以使4functionNameTypeargs,也可以让编译器用模板特化templateReturnType3根据参数自动推导类型functionNameargsfunctionNameSpecificTypeparameters如果参数类型与模板参数不匹配,编译器会尝{...}这允许为某些类型提供更高效或更适合试进行隐式类型转换,或报错的算法,同时保持函数接口的一致性类模板类模板是C++实现泛型编程的重要机制,允许定义可以处理任意类型的类类模板使用template关键字声明,后跟尖括号中的类型参数列表,形式为template typenameT或templateclass T声明类模板template typenameT classClassName{...};定义类模板在每个成员函数定义前都要重复模板声明使用类模板时必须显式指定类型ClassNameType object;类模板可以有多个类型参数,也可以为参数提供默认类型template typenameT,typename U=int类模板特化允许为特定类型提供定制实现,完全特化templateclass ClassNameSpecificType{...};,偏特化template typenameT classClassNameT*{...};C++标准库中的vector、list、map等容器都是类模板的实例异常处理基本概念异常处理是一种处理运行时错误的机制,允许程序在遇到异常情况时,将控制权转移到专门的错误处理代码,而不是立即终止程序C++的异常处理基于三个关键字try(尝试执行可能抛出异常的代码)、throw(抛出异常)、catch(捕获并处理异常)异常抛出使用throw语句抛出异常throw expression;,expression可以是任何类型(基本类型、对象、指针等)通常抛出异常对象,包含错误信息和相关数据标准库提供了std::exception基类和多个派生类(如std::runtime_error、std::logic_error等)作为异常类型异常捕获使用try-catch块捕获异常try{//可能抛出异常的代码}catchExceptionType1e{//处理类型1异常}catchExceptionType2e{//处理类型2异常}可以有多个catch块处理不同类型的异常catch...可以捕获任意类型的异常异常安全性异常安全代码确保即使发生异常也不会导致资源泄漏或不一致状态C++提供了RAII(资源获取即初始化)模式资源在构造函数中获取,在析构函数中释放,确保资源自动清理使用智能指针(std::unique_ptr、std::shared_ptr)管理动态内存可以提高异常安全性命名空间基本概念定义与使用命名空间是C++中解决名称冲突的机制,定义命名空间namespace将全局作用域分割成不同的命名区域NamespaceName{/*declarations*/}命名空间可以包含变量、函数、类、类访问命名空间中的成员型别名等各种实体,防止不同库或模块NamespaceName::memberName使中的同名标识符发生冲突C++标准库用using声明直接访问特定成员using中的所有组件都位于std命名空间中NamespaceName::memberName;使用using指令导入整个命名空间usingnamespace NamespaceName;嵌套与别名命名空间可以嵌套namespace Outer{namespace Inner{/*declarations*/}}可以为复杂的命名空间创建别名,简化访问namespace shortName=very::long::nested::nameC++17引入了嵌套命名空间的简化语法namespaceA::B::C{/*declarations*/}类的设计原则单一职责原则1每个类应该只有一个变化的理由,即只负责一项功能或相关功能集开放封闭原则/2类应该对扩展开放,对修改关闭,使用继承和组合而非修改现有代码里氏替换原则3派生类对象应该能够替换其基类对象使用,不改变程序的正确性接口隔离原则4客户端不应该依赖它不需要的接口,使用多个专用接口而非单一大接口依赖倒置原则5高层模块不应依赖低层模块,二者都应依赖抽象,使用抽象类或接口内存管理和类内存分配1C++中的类对象可以在不同内存区域创建栈上(自动变量)、堆上(使用new动态分配)、静态存储区(静态和全局对象)、常量区(const对象)栈对象在作用域结束自动销毁,堆对象需要手动使用delete释放,静态对象在程序结束时销毁资源管理2遵循RAII(资源获取即初始化)原则,在构造函数中获取资源,在析构函数中释放资源,确保资源自动管理使用智能指针(std::unique_ptr、std::shared_ptr、std::weak_ptr)管理动态内存,避免手动内存管理的错误和资源泄漏深浅拷贝3默认的拷贝构造函数和赋值运算符执行浅拷贝,只复制指针值而不是指针指向的数据管理动态资源的类需要实现深拷贝,为每个对象分配独立的资源副本,或使用引用计数技术共享资源实现三/五/零法则如果需要析构函数,通常也需要自定义拷贝构造和赋值运算符类和对象的应用实例自定义字符串类银行账户系统实现一个管理动态内存的String类,包含构造函数、析构函数、拷贝构造、设计一个银行账户类层次结构,包括基类Account和派生类SavingsAccount、移动构造、赋值运算符和其他常用操作(连接、比较、子串等)自定义CheckingAccount、LoanAccount等实现存款、取款、计算利息等操作,String类是理解内存管理、深浅拷贝和异常安全性的优秀案例展示继承、多态、虚函数和抽象类的应用class String{class Account{private:protected:char*data;string accountNumber;size_t length;double balance;public:public:String;//默认构造Accountstring accNo,double bal;Stringconst char*str;//参数构造virtual voiddepositdouble amount;Stringconst Stringother;//拷贝构造virtual boolwithdrawdouble amount=0;//纯虚函String operator=const Stringother;//赋值数~String;//析构函数virtual voiddisplayconst;};virtual~Account;};常见错误和调试技巧内存泄漏悬垂指针调试技巧忘记释放动态分配的内悬垂指针指向已释放的使用断点和调试器跟踪存是常见错误使用智内存,访问它可能导致程序执行;添加日志输能指针代替原始指针,未定义行为释放内存出关键变量值;使用静遵循RAII原则,确保为后将指针设为nullptr;态分析工具检查代码问管理资源的类实现析构避免返回局部变量的指题;创建简化测试用例函数使用内存泄漏检针或引用;注意对象生隔离问题;使用异常处测工具(如Valgrind、命周期,不要存储已销理捕获运行时错误;理AddressSanitizer)寻找毁对象的指针使用智解编译器错误信息;进泄漏注意循环引用可能指针和RAII来管理资行单元测试验证每个类能导致智能指针也发生源可以减少这类错误和函数调试包含多态内存泄漏和继承的代码时,注意观察对象的实际类型类和对象的性能优化内存布局优化复制与移动编译器优化合理排列成员变量顺序,减少内存对齐浪费;实现移动语义(移动构造和移动赋值)避免不内联小型频繁调用的函数;利用constexpr实考虑使用位域压缩小型布尔值;了解虚函数表必要的深拷贝;返回值优化(RVO)和命名返现编译期计算;避免虚函数调用的运行时开销;的内存开销,只在必要时使用多态;使用前向回值优化(NRVO);使用引用传递避免大对使用最终覆盖(final override)允许更多优化;声明减少头文件依赖,加快编译速度象复制;考虑对小型值类使用传值而非传引用,开启编译器优化选项(-O2,-O3);考虑模板性能可能更好元编程技术移动运算到编译期面向对象设计模式简介创建型模式结构型模式行为型模式创建型设计模式处理对象创建机制,包括单结构型设计模式关注类和对象的组合,包括行为型设计模式关注对象间的通信,包括观例模式(确保类只有一个实例,如日志系适配器(使不兼容接口协同工作)、桥接察者(定义对象间一对多依赖)、策略(定统)、工厂方法(定义创建对象的接口,让(将抽象与实现分离)、组合(树形结构表义算法族,使其可互换)、命令(将请求封子类决定实例化哪个类)、抽象工厂(创建示部分-整体层次)、装饰器(动态添加责装为对象)、模板方法(定义算法骨架,让相关对象家族)、建造者(分步构建复杂对任)、外观(提供统一接口)、享元(共享子类实现具体步骤)、迭代器(提供顺序访象)和原型(通过克隆创建对象)等这些细粒度对象)和代理(控制对其他对象的访问集合元素的方法)和状态(对象在状态改模式隐藏具体类的实例化过程,增加系统的问)等这些模式让不同部分协同工作,保变时改变行为)等这些模式增强系统的灵灵活性持系统灵活和高效活性和可扩展性总结与展望模式与最佳实践1设计模式与现代C++特性高级技术2泛型编程与元编程核心特性3继承、多态和运算符重载基础概念4类定义、对象创建和封装在这门课程中,我们学习了C++面向对象编程的基本概念,包括类与对象、封装、继承和多态我们探讨了类的定义、成员变量与函数、访问修饰符、构造函数与析构函数等基础知识,还学习了静态成员、友元、运算符重载等高级特性我们深入研究了继承与多态,理解了虚函数、抽象类和纯虚函数的工作原理,这些是实现可扩展和灵活的软件系统的关键我们还学习了模板、异常处理、命名空间等工具,以及内存管理、性能优化和设计模式等高级主题展望未来,C++继续发展,现代C++(C++11/14/17/20)引入了智能指针、移动语义、lambda表达式等新特性,使得面向对象编程更加高效和安全我鼓励大家继续学习和探索,将这些知识应用到实际项目中。
个人认证
优秀文档
获得点赞 0