还剩48页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
教程从基础到进阶C++欢迎学习这门面向大学计算机专业学生的完整编程指南本课程将理论与C++实践相结合,通过系统的知识点讲解,帮助你从初学者成长为能够独立开C++发项目的程序员课程概述与学习目标掌握基础语法与核心概念C++学习数据类型、控制流、函数、指针等基础知识,建立编程思维理解面向对象编程的关键思想深入学习类、继承、多态等核心概念,掌握面向对象设计方法OOP独立开发小型项目C++通过实践项目巩固所学知识,培养解决实际问题的能力为进阶学习打下坚实基础准备好迎接设计模式、并发编程等更高级的编程挑战简史与特点C++起源与发展年,比雅尼斯特劳斯特鲁普在贝尔实验室开发了的前身1979·C++C年,该语言正式命名为,表示它是语言的with Classes1983C++C增强版从此,开始了它的发展历程C++核心特点作为语言的扩展,保留了的高效性,同时增加了面向对象编程的C C++C特性它具有强大的表达能力、灵活性和兼容性,能够用于系统级编程和应用开发行业地位多年来,在编程语言排行榜上一直位居前三它被广泛应用C++TIOBE于游戏开发、高性能计算、操作系统、嵌入式系统等领域,显示了其强大的生命力和实用价值开发环境搭建集成开发环境选择编译器介绍IDE对于开发,是是平台最常用的编译器,C++Visual StudioGCC Linux平台上功能最全面的,支持多种语言标准;提供更友Windows IDEClang提供了强大的调试工具和智能提示好的错误信息和更快的编译速度;而而在跨平台开发中,是是平台的标准编译Code::Blocks MSVCWindows一个轻量级且易于使用的选择器,与完美集成VS VisualStudio配合适当的扩展也是现代开Code C++发的热门选择开发工具链配置完整的开发工具链包括编译器、链接器、调试器和构建系统使用可以跨C++CMake平台管理构建过程,而是环境下的标准构建工具配置正确的包Make UNIX/Linux含路径和库路径是解决依赖问题的关键基本结构C++头文件与命名空间使用导入所需库,通过管理名称冲突#include namespace函数与程序入口main每个程序必须有一个函数作为执行起点C++main代码注释与风格良好的注释和一致的代码风格提高可读性编译链接过程从源代码到可执行文件的转换步骤一个标准的程序通常以包含标准库头文件开始,如接着可能声明使用的命名空间,如(虽然在大型项目中不推C++#include iostreamusing namespacestd;荐这种做法)程序的执行从函数开始,返回表示程序正常结束main0数据类型
(一)基本类型类型名称典型大小值范围主要用途字节至一般整数计算int4-2^312^31-1字节至节省内存的小整数short2-32,76832,767字节平台相关大整数计算long4/8字节至单精度浮点数float4~
1.2E-
383.4E+38字节至双精度浮点数double8~
2.3E-
3081.7E+308字节至字符表示char1-128127字节或逻辑判断bool1true false的基本数据类型是构建程序的基础整型(、、、)用于表示整数值;浮点型C++int shortlong longlong(、)用于表示带小数点的数值;字符型()用于表示单个字符;布尔型()用于表示float doublechar bool真假值数据类型
(二)类型转换隐式类型转换显式类型转换当表达式中包含不同类型的操作数时,编译器会自动进行类型转提供了几种形式的显式类型转换操作符,每种都有特定的用C++换这种转换遵循一定的规则和优先级,通常是从较小的类型途转向较大的类型,以保证不丢失信息•用于基本类型间的转换,如到static_cast intfloat•整型提升和在表达式中会被提升为char shortint•用于类层次间的安全向下转型,需要运行dynamic_cast•算术转换混合类型运算中,低级类型会转换为高级类型时类型信息•用于移除或限定符const_cast const volatile•用于不相关类型间的低级转换reinterpret_cast类型转换是编程中的常见操作,但也可能导致一些微妙的问题例如,将浮点数转换为整数会截断小数部分;将较大范围的整数C++类型转换为较小范围的类型可能导致数值溢出理解这些潜在的问题对于编写健壮的代码至关重要变量与常量变量声明与初始化变量是程序中用于存储数据的命名内存位置在中,变量必须先声明后使用,可以在声明时进行初始化现代C++推荐使用初始化列表进行初始化,这种方式能防止窄化转换导致的数据丢失C++int x{10};常量定义常量是一旦初始化后值不能改变的变量使用关键字声明常量;而引入的允许在编译时计const C++11constexpr算表达式的值,提高了程序的效率常量对于提高程序的安全性和可读性非常重要作用域与生命周期变量的作用域决定了它在程序中的可见范围,而生命周期决定了它何时被创建和销毁支持块作用域、函数作C++用域、类作用域和命名空间作用域理解作用域规则对于避免命名冲突和资源管理非常重要全局变量与静态变量全局变量具有文件作用域,在整个程序生命周期内存在;关键字用于声明静态变量,它们保持其值直到程序static结束,但访问范围受限于声明它们的作用域静态变量只初始化一次,这对于保持状态信息很有用运算符
(一)算术与赋值基本算术运算符自增自减运算符包括加、减、乘、除和取模+-*/%前缀形式先修改变量值再返回结果,++i,--i这些运算符用于执行基本的数学计算,如整后缀形式先返回原值再修改变量i++,i--数相除会截断小数部分,而取模运算只适用在复杂表达式中这种区别尤为重要于整数运算符优先级与结合性复合赋值运算符乘除优先级高于加减,单目运算符高于双目如等,它们将算术操作和赋+=,-=,*=,/=运算符结合性决定了同优先级运算符的计值合并,使代码更简洁表达式等价x+=y算顺序,大多数二元运算符从左到右结合于,但前者通常更高效x=x+y运算符是构建表达式的基础,理解它们的行为对于编写正确的代码至关重要在复杂表达式中,合理使用括号可以提高代码的可读性,并确保运算按预期顺序执行运算符
(二)关系与逻辑关系运算符逻辑运算符短路求值特性包括大于、小于、大于包括与、或和非的逻辑运算符具有短路求||!C++等于、小于等于、等这些运算符用于组合多个条件,值特性在运算中,如果==于和不等于这些运创建复杂的逻辑表达式与运第一个条件为假,则不会评估==!=算符用于比较两个值,返回布算要求所有条件为真,或运算第二个条件;在运算中,如||尔类型结果或关只需一个条件为真,非运算则果第一个条件为真,则不会评true false系运算符常用于条件语句和循取反估第二个条件这可以提高效环控制中率并避免潜在错误位运算符包括按位与、按位或、|按位异或、按位取反和^~位移这些运算符直,接操作二进制位,常用于低级编程、位掩码和优化特定算法关系和逻辑运算符是构建程序决策逻辑的基础合理组合这些运算符可以创建复杂的条件表达式,控制程序的执行流程在编写条件表达式时,应注意运算符的优先级和结合性,必要时使用括号明确表达意图控制流
(一)条件语句语句与结构if if-else语句根据条件表达式的值或决定是否执行特定代码块结构允许在条件为假if truefalse if-else时执行替代代码多条件判断可以使用链接多个条件检查else if嵌套语句if语句可以嵌套使用,形成复杂的决策树虽然功能强大,但过深的嵌套会降低代码可读性在if复杂条件下,考虑使用子函数或语句替代过深的嵌套switch语句switch-case当需要基于单个变量的多个可能值执行不同操作时,语句比链更清晰高效每个switch if-else后应有语句避免贯穿执行子句处理所有未明确列出的情况case breakdefault三元条件运算符形式为,是的简洁替代,适用于简单条件选conditionvalue_if_true:value_if_false if-else择它是中唯一的三目运算符,可以嵌套使用但会降低可读性C++条件语句是控制程序执行流程的基本方式,通过评估条件表达式来决定执行哪些代码块选择合适的条件结构可以使代码更加清晰和高效如果条件逻辑过于复杂,考虑将其分解为更小的函数或使用更适合的控制结构控制流
(二)循环结构循环for循环while适用于已知迭代次数的情况,包含初始化、条适用于不确定迭代次数的情况,只要条件表达件检查和迭代表达式三部分现代中的范C++式为真就继续执行条件在每次迭代开始时检围循环提for forautoelem:container查,因此循环体可能一次都不执行供了更简洁的容器遍历方式循环控制循环do-while语句立即退出当前循环;跳过break continue与类似,但条件在每次迭代结束时检while当前迭代的剩余部分,开始下一次迭代;嵌套查,确保循环体至少执行一次适用于需要先循环中,这些语句只影响最内层循环,除非使执行操作再判断是否继续的场景用标签(不支持)C++循环是程序中处理重复任务的基本工具选择合适的循环类型可以使代码更加简洁和高效循环适合已知迭代次数的场景,和适合基for whiledo-while于条件的循环过度复杂的循环应考虑重构为多个子函数或使用容器算法替代函数基础函数声明与定义声明指定函数接口,定义提供实现参数传递机制值传递创建副本,引用传递直接操作原数据返回值与返回类型函数可返回各种类型的数据,甚至引用或指针函数重载原理同名不同参的多个函数可共存,编译器根据调用时参数自动选择函数是中实现代码重用和模块化的基本单位一个典型的函数包含返回类型、函数名、参数列表和函数体函数可以在头文件中声明,在源文件中定义,这种分离有助C++于实现接口与实现的分离,支持大型项目的组织函数进阶默认参数设置允许为函数参数指定默认值,当调用时未提供该参数,将使用默认值默认参数必须从右向左指定,即如果某个参数C++有默认值,则它右边的所有参数也必须有默认值默认参数应该在函数声明中指定,而不是在定义中内联函数优化使用关键字建议编译器将函数调用替换为函数体,避免函数调用的开销这对于简短、频繁调用的函数很有用,但inline只是对编译器的建议,不保证一定内联过度使用可能导致代码膨胀,反而降低性能递归函数设计递归函数是调用自身的函数,适合解决可以分解为相似子问题的问题,如阶乘计算、二分搜索等递归必须有基本情况(终止条件)以避免无限递归递归优雅但可能效率低下,有时可用迭代替代函数指针基础函数指针允许将函数作为参数传递或存储在变量中,增加了程序的灵活性语法较为复杂,如声明了int*fpint,int一个指向接受两个参数并返回的函数的指针在现代中,提供了更灵活的函数封装int intC++std::function这些进阶函数特性为程序员提供了强大的工具,使代码更加灵活和高效默认参数减少了重载的需要,内联优化提高了性C++能,递归提供了解决复杂问题的优雅方式,而函数指针则实现了更高级的编程模式如回调和策略模式数组基础数组声明与初始化元素访问与遍历数组是存储相同类型元素的连续内存块声明形式为,如使用索引访问数组元素,如表示第一个元素索引从开始,范围是type name[size]arr
[0]0可以在声明时初始化;或使用到不进行自动边界检查,越界访问可能导致未定义行为数int arr
[5]int arr
[3]={1,2,3}0size-1C++的统一初始化语法未指定的元素将被默认组可以通过循环遍历,现代支持范围循环C++11int arr
[3]{1,2,3}C++for forautoelem:arr初始化(对于内置类型通常是)0数组作为函数参数数组与指针的关系将数组传递给函数时,实际传递的是指向数组第一个元素的指针,而不是整数组名在大多数上下文中会衰变为指向第一个元素的指针例如,和arr个数组的副本因此,函数内对数组元素的修改会影响原数组通常需要同通常等价但有少数例外,如使用或运算符时指针算术arr
[0]sizeof时传递数组大小,因为指针本身不包含数组长度信息可用于数组遍历,如等同于*arr+i arr[i]多维数组二维数组声明与初始化内存布局与访问模式二维数组可以看作数组的数组,声明形式为中的多维数组以行优先顺序存储,即同一行的元素在内存中相邻type name[rows][cols]C++可以使用嵌套初始化列表进行初始化这意味着按行遍历比按列遍历更高效,因为它更符合缓存访问模式int matrix
[3]
[4]={访问二维数组元素使用两个索引访问第行第列的元素{1,2,3,4},matrix[i][j]i j与一维数组一样,索引从开始,不进行边界检查{5,6,7,8},0{9,10,11,12}理解多维数组的内存布局对优化性能和避免错误至关重要,特别是在处};理大型数据集时中也可以使用C++11intmatrix
[3]
[4]{{1,2,3,4},{5,6,7,8},{9,10,11,12}};多维数组在科学计算、图像处理和游戏开发等领域有广泛应用例如,在图像处理中,一个二维数组可以表示图像的像素矩阵;在游戏开发中,可以用来表示游戏棋盘或地图字符串处理风格字符串C风格字符串是以空字符结尾的字符数组例如;这实际上是一个包含C\0char str[]=Hello个字符的数组,最后一个是空字符风格字符串操作通常使用头文件中的函数,如6C cstring计算长度,复制字符串,连接字符串等strlen strcpystrcat类std::string标准库提供的类是处理字符串的现代方式,定义在头文件中相比风格字C++string string C符串,提供了自动内存管理,避免了缓冲区溢出的风险它支持直接使用运算符连std::string+接字符串,使用比较字符串,并提供了丰富的成员函数如、、等==substr findreplace字符串流的头文件提供了字符串流类,如(输入字符串流)和C++sstream istringstream(输出字符串流)这些类可以将字符串转换为其他类型的数据,或将各种ostringstream类型的数据转换为字符串,特别适合格式化输出和解析输入在现代编程中,几乎总是比风格字符串更好的选择它不仅更安全(避免缓冲区溢C++std::stringC出),而且提供了更丰富的功能和更直观的接口只有在特定场景,如与交互或极端性能优化时,C API才需要使用风格字符串C指针基础指针的灵活应用动态内存管理、数据结构实现、多态性支持指针操作解引用、地址获取、指针算术*p xp++指针与内存指针存储内存地址,建立数据间的关联指针基本概念变量存储内存位置而非直接数据指针是中最强大也最容易出错的特性之一从本质上讲,指针是存储内存地址的变量通过指针,我们可以间接访问和修改存储在特定内存位置的数据C++指针的声明形式为,如;赋值形式为,其中获取变量的地址;解引用形式为,获取指向的值type*name int*ptr ptr=var varvar*ptr ptr指针与内存1动态内存分配使用运算符在堆上分配内存,返回指向该内存的指针例如创建一个new int*p=new int10存储值的整数数组分配形式为,创建包含个整数的数组动态分配10int*arr=new int
[5]5的内存在程序运行期间一直存在,直到显式释放2内存释放使用运算符释放由分配的单个对象的内存;使用释放由分配的delete newdelete pdelete[]new[]数组内存忘记释放动态分配的内存会导致内存泄漏,最终可能耗尽系统资源一个delete[]arr良好的做法是在释放后将指针设为nullptr指针算术指针支持算术运算,如加法、减法和比较这些操作考虑指针类型的大小,例如,如果是,则p int*指向下一个整数位置(而不仅仅是下一个字节)指针算术在数组处理中特别有用,但需要小心p+1避免越界访问智能指针现代提供了智能指针作为原始指针的安全替代实现了独占所有权模型,保证资C++std::unique_ptr源只有一个拥有者;当智能指针超出作用域时,它会自动释放所拥有的资源,大大减少了内存泄漏的风险引用类型引用的本质与特性引用与指针的关键区别引用是变量的别名,提供了一种间接访问变量的方式与指针不同,•引用必须初始化,指针可以后赋值引用一旦初始化,就无法更改为引用其他对象引用必须在声明时初•引用不能为空,指针可以为nullptr始化,没有空引用的概念•引用不能重新绑定到其他对象引用的声明形式为type name=var,如int r=x;此后,r•引用没有多级间接性(无引用的引用)的任何使用都等同于直接使用从内部实现看,引用通常作为指针x•引用使用更直观,不需要解引用操作实现,但提供了更安全、更便捷的语法由于这些特性,引用通常更安全,而指针则更灵活在现代中,C++引用常用于参数传递和返回值,而指针则主要用于动态内存管理和表示可选或可变关系引用最常见的用途是作为函数参数通过引用传递可以避免值传递的复制开销,同时允许函数修改传入的参数对于大型对象,使用引用const传递()可以既避免复制又防止修改原对象,这是一种常见的优化技术const type结构体struct结构体的定义与初始化结构体成员访问结构体是用户定义的复合数据类型,将多个不同类型的数据组合在一起在中,结构体使使用点运算符访问结构体变量的成员,如;使用箭头运算符访问结构体指针的成员,C++.pt.x-用关键字定义,如现代支持多种初始化方式,如等同于中的结构体成员默认为公有,这与类不同,后者的成员默认为struct structPoint{int x;int y;};C++ptr-x*ptr.x C++包括直接初始化、统一初始化和聚合初始化私有结构体数组与指针结构体作为函数参数可以创建结构体数组,每个元素都是一个结构体实例,如可以使用指针结构体可以作为函数参数传递,默认情况下是值传递(创建副本)对于大型结构体,为避免Point points
[100];指向结构体,这在动态分配和传递大型结构体时很有用,如复制开销,通常使用引用或指针传递在中,结构体也可以作为函数的返回值,编译器会Point*ptr=new Point{1,2};C++结构体也可以包含指针成员,用于创建复杂的数据结构如链表和树优化以减少不必要的复制结构体是中组织相关数据的基本方式,特别适合表示具有明确属性的实体,如几何形状、记录或游戏对象在中,结构体不仅可以包含数据成员,还可以包含成员函数、构造函数和析构函数,这C++C++使得它们在功能上与类非常相似枚举类型enum1传统枚举类型中的传统枚举使用关键字定义,如枚举常量默C++enum enum Color{RED,GREEN,BLUE};认从开始递增,但可以显式指定值,如0enumColor{RED=1,GREEN=2,BLUE=4};传统枚举的值会隐式转换为整数,并且全局可见,这可能导致名称冲突和类型安全问题2强类型枚举C++11引入了强类型枚举,使用或关键字定义,如C++11enum classenum structenum classColor强类型枚举提供了更好的类型安全性枚举常量必须使用作用域运算符{RED,GREEN,BLUE};访问(如),不会隐式转换为整数,也不会导致名称冲突强类型枚举可以指定底层类Color::RED型,如enum classColor:uint8_t{...};3应用场景与实践枚举类型适用于表示一组离散的值,如颜色、状态、选项等它们使代码更加清晰和自文档化在实践中,强类型枚举通常是更好的选择,除非需要与代码互操作或进行位操作(这时传统枚举更方C便)枚举常与语句结合使用,处理不同枚举值的情况编译器通常会为缺少的枚举值发switch case出警告,这有助于确保完整性枚举类型是构建类型安全和表达性强的程序的重要工具它们不仅提高了代码的可读性和维护性,还有助于捕C++获逻辑错误例如,当函数期望一个特定的枚举类型时,尝试传递错误类型的值会导致编译错误,而不是在运行时产生难以调试的问题面向对象编程基础继承允许一个类(派生类)基于另一个类(基类)定义,继承其特性和行为继承促进了代码重用,2建立了类之间的层次关系,支持是一种的概念封装模型支持单继承、多继承和虚继承C++将数据和操作数据的方法捆绑在一起,隐藏对1象内部细节,只暴露必要的接口封装通过访问修饰符(、、)控public privateprotected多态制对类成员的访问,保护数据的完整性和一致性使不同类型的对象对同一操作做出不同响应的能力通过虚函数实现运行时多态,允许通过C++基类指针或引用调用派生类的方法多态增强了3代码的灵活性和可扩展性,是设计模式的基础面向对象编程()是一种以对象为中心的编程范式,将数据和行为组织成相互交互的对象作为一种多范式语言,既支持面向过程编程,也全面支持OOP C++面向对象编程从结构体到类的演进体现了从简单数据聚合到具有行为和封装性的完整对象的转变类与对象
(一)基本结构类的声明与定义类是中创建对象的蓝图,使用关键字声明类声明通常放在头文件中,而定义可以分离到源文件C++class中,这有助于实现接口与实现的分离类的声明包括数据成员(属性)和成员函数(方法)的声明,而定义则提供成员函数的实现成员变量与成员函数成员变量表示对象的状态或特性,通常是私有的以实现封装成员函数操作对象的数据,定义对象的行为成员函数可以访问对象的所有成员,包括私有成员用关键字标记的成员函数承诺不修改对象状态,const可以被对象调用const访问修饰符提供三种访问级别(任何代码都可以访问)、(只有类成员和友元可以访问)和C++public private(类成员、友元和派生类可以访问)这些修饰符控制类成员的可见性和可访问性,是实现封装protected的关键机制最佳实践是将数据成员设为私有,通过公有方法提供受控访问对象的创建与使用对象是类的实例,可以通过多种方式创建自动变量(栈上)、动态分配(堆上,使用)或作为其他对new象的成员一旦创建,可以使用点运算符(对象成员)或箭头运算符(指针成员)访问对象的公有成.-员对象在超出作用域或显式删除时销毁类与对象
(二)构造函数默认构造函数没有参数或所有参数都有默认值的构造函数当类没有定义任何构造函数时,编译器会提供一个隐式的默认构造函数,它不执行任何初始化用的语法可以显式要求编译器生成默认构造函数默认构造函数在创建对象数组或使用容器时特别重要C++11=default参数化构造函数接受一个或多个参数的构造函数,用于在创建对象时初始化其状态参数化构造函数可以有默认参数值,使其在某些调用情况下表现得像默认构造函数引入了委托构造函数,允许一个构造函数调用同一类的另一个构造函数,减少代码重复C++11复制构造函数接受同类对象的常引用为参数的构造函数,用于创建对象的副本当对象通过值传递、用作函数返回值或显式复制时,会调用复制构造函数如果类管理资源(如动态内存),通常需要自定义复制构造函数以实现深拷贝,避免多个对象共享同一资源移动构造函数C++11接受右值引用参数的构造函数,用于窃取临时对象或即将销毁对象的资源,避免不必要的复制操作移动构造函数是引入的高C++11效资源传输机制,在处理大型对象或资源密集型对象时特别有用它通常与移动赋值运算符一起实现构造函数是类的特殊成员函数,与类同名且没有返回类型,负责初始化新创建的对象良好的构造函数设计对于确保对象始终处于有效状态至关重要构造函数可以使用成员初始化列表,这通常比在函数体内赋值更高效,特别是对于成员和引用成员,初始化列表是必需const的类与对象
(三)析构函数析构函数的作用与特点析构函数是与类同名但以波浪号为前缀的特殊成员函数,没有参数和返回值,如它在~~ClassName对象被销毁时自动调用,负责执行必要的清理工作,特别是释放对象占用的资源当对象超出作用域、程序结束或使用显式销毁时,析构函数会被调用delete资源管理与释放析构函数最重要的职责是释放对象在生命周期内获取的资源,如动态分配的内存、打开的文件、数据库连接等如果类的成员管理了资源,析构函数必须确保这些资源被正确释放,以防止资源泄漏对于动态分配的内存,应使用或释放;对于其他资源,应调用相应的释放函数delete delete[]虚析构函数的必要性当通过基类指针删除派生类对象时,如果基类的析构函数不是虚函数,只会调用基类的析构函数,而不会调用派生类的析构函数,这可能导致资源泄漏因此,任何可能作为基类的类都应该有虚析构函数这确保了当通过基类指针删除对象时,调用正确的析构函数链virtual~BaseClass{}RAII设计模式资源获取即初始化是中的关键设计模式,将资源的生命周期绑定到对象的生命周期在构造函RAII C++数中获取资源,在析构函数中释放资源,确保资源管理的安全性和异常安全性是资源管理的推RAII C++荐方式,智能指针和就是的典型应用std::unique_ptr std::shared_ptr RAII类的特殊成员函数赋值运算符重载赋值运算符重载允许一个对象的值复制给另一个对象标准形式是=ClassName operator=const实现时应处理自赋值情况,确保正确复制所有成员,并返回以支持链式赋ClassName other*this值与复制构造函数类似,管理资源的类通常需要自定义赋值运算符以实现深拷贝移动赋值运算符C++11移动赋值运算符接受右值引用参数它通过窃取ClassName operator=ClassName other右值对象的资源并将右值对象留在有效但不确定的状态,实现资源的高效转移这避免了不必要的复制,对于处理大型对象特别有用移动赋值运算符通常与移动构造函数配对实现复制控制与资源管理的三法则指出,如果一个类需要自定义析构函数、复制构造函数或赋值运算符中的任何一个,它通C++常需要全部三个扩展为五法则,加入了移动构造函数和移动赋值运算符这些特殊成员函数C++11共同控制对象的复制、移动和销毁行为,对资源管理至关重要默认删除函数/引入了和说明符,用于显式控制特殊成员函数的生成要求编译器生C++11=default=delete=default成默认实现,如,这比空实现更高效禁止使用特定函数,如ClassName=default;=delete防止对象被复制,这是实现不可复制类的简洁方式ClassNameconst ClassName=delete;类的静态成员静态成员变量特性静态成员函数特性静态成员变量是属于类而非对象的变量,被该类的所有实例共享它在静态成员函数也属于类而非对象,可以访问类的静态成员,但不能访问类定义中声明(使用关键字),但必须在类外部定义静态成员非静态成员(因为它们与特定对象无关)静态成员函数没有指针,static this变量存在于全局数据区,生命周期与程序相同,即使没有类的实例,静因此不能被声明为、或constvolatilevirtual态成员变量也存在静态成员函数的调用方式与静态成员变量类似,可以通过类名调用静态成员变量可以是公有或私有的,访问控制规则同样适用可以通过,也可以通过对象调用ClassName::staticFunc类名和作用域解析运算符访问,也可以通过静态成员函数常用于操作静态成员变量、提供与ClassName::staticVar object.staticFunc对象访问静态成员变量常用于跟踪对象数量、共类相关但不依赖于对象状态的功能,以及作为构造器方法实现工厂模式object.staticVar享常量和实现单例模式或单例模式静态成员是类系统中的重要组成部分,为共享数据和实现与类相关的功能提供了便捷机制它们与全局变量和函数相比,提供了更好的封装性和C++类型安全性,同时保持了便捷的访问方式在设计模式中,静态成员被广泛用于实现单例模式、工厂模式等运算符重载基础运算符重载的语法与限制成员函数友元函数重载常见运算符重载示例vs运算符重载允许自定义类型使用内置运算符,使代码更运算符可以作为成员函数或非成员函数(通常是友元)重载常见的重载包括算术运算符、、、用于自定义数值C+++-*/自然直观重载形式为返回类型运算符参数列成员函数形式中,左操作数必须是调用对象,只接受右操作类型;比较运算符、、、用于实现对象比较;下标operator==!=表允许重载大多数运算符,但有一些限制不能改变数作为参数;非成员函数形式则接受所有操作数作为参数运算符用于实现类似数组的访问;函数调用运算符用C++[]运算符优先级、结合性或操作数数量;不能创建新运算符;某些运算符(如、、、)必须作为成员函数重载;于创建函数对象;增量减量运算符、用于实现迭代=[]-/++--某些运算符如、、、等不能重载而输入输出运算符、通常作为友元函数重载器等;赋值运算符和复合赋值运算符、用于自定..*:::=+=-=义资源管理运算符重载是的强大特性,能够使自定义类型的使用更加自然和直观通过重载,可以让复杂对象(如矩阵、向量、字符串等)使用熟悉的运算符语法,提高代码的可读性和表达能C++力然而,这种能力也应当谨慎使用,遵循最小惊奇原则,确保重载的行为符合直觉预期友元机制friend友元打破封装的利弊友元类的概念与应用友元机制提供了一种破除封装边界的方式,这在某些情况下是友元函数的声明与使用友元类是一个可以访问另一个类的私有和保护成员的类在被必要的,但也可能被滥用友元打破了数据隐藏原则,使类的友元函数是一个不属于类成员但有权访问类的私有和保护成员访问类中使用声明友元关系友元实现细节暴露给特定的外部实体,这可能增加代码的耦合性和friend classClassName;的函数在类内部使用friend关键字声明friend类的所有成员函数都可以访问被声明友元的类的私有和保护成脆弱性然而,在需要密切合作的类之间,友元可以提供高效returnType functionNameparameters;友元函数可以员友元关系不是对称的(A是B的友元不意味着B是A的友访问而不需要通过公共接口的间接层,在运算符重载、迭代器是普通函数,也可以是其他类的成员函数友元关系不具有传元),也不具有传递性友元类常用于紧密协作的类之间,如设计等场景中特别有用递性(是的友元,是的友元,不意味着是的友元)迭代器与容器、嵌套类与外部类等A BB C A C和继承性(派生类不继承基类的友元关系)友元是提供的一种控制访问权限的特殊机制,它允许特定的非成员函数或类访问另一个类的非公开成员尽管友元在理论上违背了严格的封装原则,但在实际编程中,它解决了许多实际问C++题,特别是那些需要密切协作的组件之间的问题继承基础多态使用与动态绑定通过基类指针引用操作派生类对象/函数覆盖与扩展派生类重定义或扩展基类功能类层次结构设计建立是一种关系的类型体系继承语法与机制4基类到派生类的特性传递继承是面向对象编程的核心机制,允许一个类(派生类)基于另一个类(基类)定义,继承其特性和行为的继承语法是C++class Derived:[access-specifier],其中可以是、或,默认为(与不同,默认为)Base access-specifier public protected privateprivate structpublic继承类型与访问控制基类成员继承类型公有继承保护继承私有继承/publicprotected private成员public publicprotected private成员protected protectedprotectedprivate成员不可访问不可访问不可访问private提供了三种继承类型,每种都定义了基类成员在派生类中的访问级别C++公有继承表示是一种关系,基类的公有成员在派生类中仍为公有,保护成员仍为保护这是最常用的继承类型,允许派生类对象用于任何需要基类对public象的地方保护继承中,基类的公有和保护成员在派生类中都变为保护成员这种继承通常用于类库实现中的中间基类,限制了基类接口对派生类用户的暴protected露私有继承中,基类的公有和保护成员在派生类中都变为私有成员这种继承表示使用了一个关系而非是一种关系,通常可以通过组合替代私有private继承中,派生类对象不能转换为基类引用或指针多重继承多重继承的语法与实现多重继承允许一个类从多个基类派生,语法为class Derived:[access-specifier1]Base1,[access-每个基类可以有不同的访问说明符多重继承使得一个类可以同时具有多个基类的specifier2]Base2,...特性,例如,一个飞行汽车类可以同时继承汽车和飞机类的功能菱形继承问题菱形继承(也称钻石继承)发生在类继承自类和类,而和都继承自类的情况,形成菱形结构这D B C BCA会导致中包含的两份副本,一份来自,一份来自,从而引发歧义和资源浪费例如,当中访问的D ABCD A成员时,编译器无法确定应该访问哪一份,需要显式指定或B::A_member C::A_member虚继承解决方案虚继承是提供的解决菱形继承问题的机制通过在继承声明中加入关键字(如C++virtual classB:virtual),可以确保共同基类只有一个实例虚继承的核心思想是共享而非复制公共基类,确保在最终public AA派生类中只存在一份公共基类的子对象,消除了歧义和重复多重继承的最佳实践虽然多重继承功能强大,但也容易导致复杂性和维护困难使用时应遵循一些最佳实践尽量避免深层继承结构;优先考虑单继承和组合;使用接口(纯虚基类)进行多重继承而非具体实现;必要时使用虚继承;避免在不同继承路径上覆盖同名方法;编写清晰的文档说明类的继承关系多态性原理多态的概念与重要性动态绑定与虚函数表多态是面向对象编程的核心特性,允许不同类型的对象对相同的消息(函数通过虚函数表()机制实现运行时多态当类声明虚函数时,编C++vtable调用)做出不同的响应支持两种形式的多态译器会为该类创建一个虚函数表,其中包含指向该类所有虚函数实现的指针C++每个对象包含一个指向其类虚函数表的隐藏指针()vptr•编译时多态(静态多态)通过函数重载和模板实现当通过基类指针或引用调用虚函数时,实际调用哪个函数不是在编译时确定•运行时多态(动态多态)通过虚函数和继承实现的(静态绑定),而是在运行时根据对象的实际类型查询虚函数表来确定的多态增强了代码的灵活性和可扩展性,是开放封闭原则(对扩展开放,对(动态绑定)这允许同一段代码对不同类型的对象产生不同的行为修改封闭)的基础通过多态,可以编写处理基类对象的通用代码,而这些虚函数表机制有一定的性能开销每个对象增加一个指针的空间开销,每次代码能够自动适应派生类的特定行为虚函数调用需要额外的间接查表操作但这种开销通常很小,并且换来了巨大的灵活性收益运行时类型识别()是提供的一组机制,用于在运行时获取和使用对象的类型信息主要通过两种方式实现RTTI C++RTTI运算符用于安全地将基类指针或引用转换为派生类指针或引用,如果对象不是目标类型,转换失败(指针返回,引用抛出异常)dynamic_cast nullptr运算符返回对象的类型信息,可以用于比较类型或获取类型名称typeid虚函数与抽象类虚函数声明与实现纯虚函数与接口定义抽象类特性与用途虚函数使用关键字声明,允许派生纯虚函数是没有实现的虚函数,使用语抽象类是定义接口和部分实现的理想方virtual=0类覆盖(重写)基类的实现格式为法声明式,为派生类提供统一的基础抽象类可virtual returnType包以包含普通方法、数据成员和构造函数,virtual returnTypefunctionNameparameters=0;基类中含至少一个纯虚函数的类被称为抽象类,为派生类提供共享功能虽然不能创建抽functionNameparameters;的虚函数可以有默认实现,派生类可以选不能直接实例化,只能作为基类使用纯象类的实例,但可以创建指向派生类的抽择是否覆盖一旦函数被声明为虚函数,虚函数的目的是定义接口,强制派生类提象类指针或引用,这是多态的基础抽象在所有派生类中它都保持虚函数特性,即供实现只包含纯虚函数的类类似于其他类常用于框架设计,定义组件的接口规使派生类没有使用关键字(但为清语言中的接口()范virtual interface晰起见,建议仍然使用)覆盖与隐藏覆盖()发生在派生类实现与基override类虚函数同名同参数的函数时引C++11入了关键字,可以明确表明派生override类函数是覆盖基类的虚函数returnTypefunctionNameparameters这有助于捕获拼写错误或签override;名不匹配等常见错误隐藏()发生hide在派生类定义与基类非虚函数同名的函数,或参数不同的同名函数时,这种情况下基类函数在派生类中不可见,但不是多态行为异常处理基础语句块try包含可能引发异常的代码语句throw发现错误时抛出异常对象处理器catch捕获并处理特定类型的异常异常传播4未捕获的异常沿调用栈向上传递异常处理是提供的结构化错误处理机制,允许程序检测运行时错误并将控制转移到专门设计的错误处理代码基本结构包括块、处理器和语句块包围可能引发C++try catchthrow try异常的代码;当检测到错误时,使用语句抛出异常对象;与块关联的处理器尝试捕获异常并处理错误throw trycatch标准库定义了一个异常层次结构,所有标准异常都派生自基类常见的标准异常包括(运行时错误)、(逻辑错误)、C++std::exception std::runtime_error std::logic_error(内存分配失败)等自定义异常通常也应继承自,并覆盖方法提供错误描述std::bad_alloc std::exception what异常处理进阶函数try块与构造函数异常noexcept说明符C++11函数块是一种特殊语法,允许在函数体外捕获函数体内抛出的异常,格式为引入了说明符,表明函数不会抛出异常如果try try:C++11noexcept voidfunc noexcept;这对构造函数特别有用,因为它们没有返回值表示失败函数抛出异常,程序会调用终止还可以带条件function...{...}catch...{...}noexcept std::terminate noexcept特别是在成员初始化列表中可能抛出异常的情况下,函数块允许捕获并处理这些异常,确保,为时函数不抛出异常优化允许编译器生try noexceptexpressionexpression truenoexcept资源的正确清理和对象的一致状态成更高效的代码,特别是在移动操作和析构函数中现代中,析构函数默认为C++,移动操作应当尽可能声明为noexcepttrue noexcept异常安全性级别资源管理与异常处理定义了三个异常安全性级别基本保证(发生异常后,程序处于有效但可能不是期望的状异常可能在任何点抛出,包括资源获取和释放之间,这可能导致资源泄漏(资源获取即C++RAII态);强保证(发生异常后,程序状态不变,好像函数没有被调用);不抛出保证(函数不会初始化)模式是解决这个问题的关键将资源的生命周期绑定到对象的生命周期,在构造函数抛出异常)设计函数时应明确其异常安全级别,并在文档中说明强保证通常通过复制并交中获取资源,在析构函数中释放资源当异常导致栈展开时,局部对象的析构函数会自动调用,换技术实现先创建新状态的副本,然后原子地交换,确保修改要么完全成功,要么完全失败确保资源被释放智能指针和标准库容器都遵循,提供了异常安全的资源管理RAII模板基础模板参数与类型推导函数模板语法与实例模板参数可以是类型参数或typename/class函数模板是一种泛型编程工具,允许创建可以处非类型参数具体值如整数编译器能够从C++理不同类型的函数模板使用关键字template函数参数自动推导模板类型,但返回类型必须显定义,如template TmaxT a,T b式指定或通过后置返回类型语法标记C++11调用时可以显式{return aba:b;}引入了和,与模板配合提供更灵auto decltype指定类型或让编译器自动推导类max10,20活的类型处理型max10,20模板编译模型显式实例化与特化使用包含模型编译模板模板定义需要在显式实例化创建模板的特定类型版本C++使用点可见,通常放在头文件中编译器遇到模模板特化为特定类template voidfuncint;3板实例化时生成特定类型的代码,这称为模板实型提供不同实现template void例化不同翻译单元可能实例化相同模板,最终特殊处理特化允funcstd::string x{/**/}链接器会去除重复定义许针对特定类型优化性能或处理特殊逻辑模板是实现泛型编程的核心机制,允许编写与类型无关的通用代码,同时保持类型安全和高效率与运行时多态(通过虚函数实现)不同,模板实现编译C++时多态,没有运行时开销标准库大量使用模板,如容器、算法和智能指针等类模板类模板定义与使用类模板是创建类族的蓝图,允许类使用未指定的类型参数定义格式为使用类模板必须显式指定类型参数,不像函数模板可以自动推导类模板广泛应用于template classClassName{...};ClassName obj;容器、智能指针和适配器等通用组件中,是标准库的基础C++模板成员函数实现类模板的成员函数可以在类定义内部实现,也可以在外部实现,但外部实现需要指定它属于一个模板类类模板也可以包含非模板成员、静态成员template returnTypeClassName::methodName...{...}和嵌套类型成员函数只有在被调用时才会实例化,这被称为延迟实例化或按需实例化,有助于减少代码膨胀模板参数高级特性类模板参数可以有默认值,简化常见情况下的使用模板参数可以是非类型参数,如整数常量引入了可变参数模板,使模板能够接受任template classMyClass{...};template classArray{...};C++11意数量的参数模板还可以使用模板模板参数,接受另一个模板作为参数,这在构建高度灵活的库时非常有用template classTuple{...};类模板是泛型编程的强大工具,允许创建高度可重用、类型安全的通用组件通过类模板,可以实现与类型无关的数据结构和算法,同时保持编译时类型检查和运行时性能标准库容器如、和都是类模板的典型应用,它们能够存储任何类型C++std::vector std::list std::map的元素,同时提供类型安全的操作概述STL标准模板库的组成部分标准模板库是标准库的核心部分,提供了一组通用的模板类和函数的主要组件包括容器(如、STL C++STL vector、)、算法(如、、)、迭代器(连接容器和算法)、函数对象(如仿函数和谓词)、适list mapsort findtransform配器(如、)以及分配器(管理内存分配)这些组件共同构成了一个强大的通用编程框架stack queue容器、算法、迭代器的核心理念是将数据存储(容器)与数据处理(算法)分离,并通过迭代器连接二者容器负责高效存储和访问数STL据,提供了不同的数据结构如向量、链表、树等算法实现了常见操作如排序、搜索、转换等,它们不直接操作容器,而是通过迭代器访问数据迭代器提供了统一的接口,允许算法以相同的方式处理不同类型的容器函数对象与适配器函数对象(仿函数)是行为类似函数的对象,通过重载实现它们比普通函数更灵活,可以保持状态、作为operator模板参数传递并利用内联优化提供了多种预定义的函数对象如、,以及函数适配器如、STL lessgreater bindnot1等容器适配器(如、、)修改基础容器的接口,提供特定的数据结构语义迭代器适配stack queuepriority_queue器(如、)改变迭代器的行为,增加新功能reverse_iterator insert_iteratorSTL的设计哲学的设计基于几个关键原则泛型编程(使用模板实现类型无关的代码);抽象分离(将数据结构与算法分离);效STL率(零开销抽象,性能接近手写代码);灵活性(组件可以自由组合);一致性(统一的命名和接口约定)的设STL计哲学极大地影响了现代编程风格,推动了泛型编程和组件化设计的普及C++容器
(一)序列容器STL容器类型内部实现随机访问插入删除效率迭代器稳定性/动态数组尾部,中间插入可能导致失vector O1O1效On双向链表任意位置始终有效list On O1分段数组两端,中间插入可能导致失deque O1O1效On固定数组不支持插入删除始终有效array O1/序列容器在中是基础的线性数据结构,按照一定顺序存储元素是最常用的序列容器,实现为可动STL std::vector态增长的数组它提供快速的随机访问,在尾部添加元素通常很高效(摊销常数时间),但在中间插入或删除需要移动后续元素特别适合需要频繁随机访问元素的场景vector实现为双向链表,支持任意位置的常数时间插入和删除,但不支持随机访问,必须遍历到特定位置的std::list list优势在于插入和删除操作不会使迭代器失效(除了指向被删除元素的迭代器)(双端队列)提供了类std::deque似的随机访问,并且支持两端的常数时间插入删除,但内部实现更复杂,通常内存开销略大引入vector/C++11的是固定大小数组的封装,提供了容器接口而无动态分配开销,适合大小固定的场景std::array STL选择合适的序列容器取决于具体需求如果需要随机访问和动态大小,选择;如果需要频繁在任意位置插入vector删除,选择;如果需要在两端频繁操作,选择;如果大小固定且需要最大性能,选择理解不同/list dequearray容器的性能特点对于编写高效代码至关重要容器
(二)关联容器STLset与multiset是存储唯一元素的有序容器,基于红黑树实现它提供了对元素的快速查找、插入和删除操作,通常是对数复杂度std::set元素默认按升序排列,但可以提供自定义比较函数的特点是不允许重复元素,而且元素一旦插入就不能修改Olog nset(因为修改可能破坏排序)与类似,但允许存储重复元素这些容器特别适合需要快速查找和自动排序的场std::multiset set景map与multimap是存储键值对的有序容器,也基于红黑树实现每个键只能出现一次,并与一个值关联支持通过键的快速std::map map查找、插入和删除(对数复杂度),并提供了方便的下标操作符与类似,键一旦插入就不能修改,map[key]=value set但关联的值可以修改允许一个键关联多个值,适用于需要一对多关系的场景容器在实现字典、查找std::multimap map表等数据结构时非常有用无序容器C++11引入了四种无序容器、、和C++11unordered_set unordered_multiset unordered_map unordered_multimap这些容器基于哈希表实现,提供了常数时间复杂度的平均查找、插入和删除操作与有序容器不同,无序容器不维护元素顺序,元素的位置由其哈希值决定哈希容器需要一个哈希函数和相等比较函数,标准库为常见类型提供了默认实现在不需要元素有序且追求最大性能的场景下,无序容器通常是更好的选择性能比较与选择关联容器的选择应基于具体需求如果需要元素有序,选择;如果对顺序无要求但需要最快的查找,选择set/map有序容器的操作复杂度为,而无序容器的平均复杂度为,最坏情unordered_set/unordered_map Olog nO1况为(当发生哈希碰撞时)有序容器额外提供了范围查找和顺序迭代的能力,而无序容器通常在内存使用上不On如有序容器高效在处理大量数据时,这些性能差异尤为显著,可能成为决定应用性能的关键因素关联容器为存储和检索键值数据提供了强大的机制,是实现复杂数据结构和算法的基础后,提供了完整的关联容器家族,C++11STL涵盖了有序无序和唯一多重的各种组合,几乎能满足所有关联数据存储的需求理解这些容器的特性和性能权衡,对于选择合适的//数据结构解决问题至关重要算法STL算法库提供了丰富的通用算法,可以对容器中的元素进行各种操作这些算法分为几大类非修改序列操作(如、)、修改序列操作(如、STL findcount copy)、排序和相关操作(如、)、数值操作(如)等所有算法都通过迭代器操作数据,使它们能够与任何提供合适迭代器的容器配合使transform sortmerge accumulate用引入的表达式极大地简化了算法的使用,允许直接在调用点定义简短的函数对象使用和可以简洁地替代许多传统循环,如C++11lambda for_each lambda算法的设计注重效率和通用性,许多算法有线性时间复杂度,而排序相关算法通常为for_eachv.begin,v.end,[]int n{coutn;};STL Onlogn理解并善用这些算法可以写出更简洁、更高效的代码,同时减少错误的可能性迭代器体系随机访问迭代器最强大的迭代器,支持所有操作双向迭代器支持前进和后退,但不能随机访问前向迭代器只能向前移动,但可多次遍历输入输出迭代器/最基本的读写访问,只能单次遍历迭代器是的核心概念,提供了一种统一的方式来遍历和操作不同容器中的元素迭代器充当容器和算法之间的桥梁,使算法能够独立于具体容器类型工作定义了STL STL五类迭代器,每类提供不同级别的功能输入迭代器支持读取元素并向前移动;输出迭代器支持写入元素并向前移动;前向迭代器结合了输入和输出能力,且可以多次遍历;双向迭代器增加了向后移动的能力;随机访问迭代器提供了最完整的功能,包括随机访问和指针算术不同容器提供不同类型的迭代器和提供随机访问迭代器;和提供双向迭代器;提供前向迭代器迭代器适配器如反vector arraylist mapforward_list reverse_iterator转遍历方向,在指定位置插入元素而不是覆盖自定义迭代器需要实现特定接口,包括解引用、递增等操作符理解迭代器类别及其操作是有效使insert_iterator*++用的关键,也是设计通用算法的基础STL智能指针详解std::unique_ptr std::shared_ptr实现了独占所有权模型,一个资源只能被一个实现了共享所有权模型,允许多个指针引用同一资源std::unique_ptr std::shared_ptr拥有当被销毁或重新赋值时,它所管理的资它使用引用计数跟踪有多少指向同一对象,当最后一个引unique_ptr unique_ptr shared_ptr源会自动释放这种智能指针不允许复制(复制构造函数和赋值运算符用被销毁时才释放资源支持复制和赋值,每次操作都会shared_ptr被删除),但支持移动语义,可以转移所有权更新引用计数创建方式创建方式,这种std::unique_ptr ptr=std::make_uniqueargs...std::shared_ptr ptr=std::make_sharedargs...()或()方式更高效,因为它只分配一次内存(同时保存对象和控制块)C++14std::unique_ptr ptrnewTypeargs...C++11非常轻量,没有额外开销,是大多数单一所有权场景的首有轻微的性能开销,但在需要共享资源的场景中非常有用,unique_ptr shared_ptr选如图形或数据结构中的节点是的一个特殊伙伴,它观察管理的对象但不增加引用计数这解决了可能导致的循环引用问题,std::weak_ptr shared_ptr shared_ptr shared_ptr如两个对象相互持有会导致内存泄漏不能直接访问对象,必须通过方法获取临时,如果原对象已销毁则shared_ptr weak_ptr lockshared_ptr获取空指针智能指针可以配置自定义删除器,处理特殊资源的释放例如,确保文件句柄在离开作用域std::unique_ptr filefopenfile.txt,r,fclose;时自动关闭智能指针是现代内存管理的核心,遵循原则,极大减少了内存泄漏和资源泄漏的风险在新代码中应优先使用智能指针替代C++RAII原始指针,特别是涉及所有权管理的场景新特性
(一)C++11auto类型推导范围for循环初始化列表nullptr关键字关键字允许编译器根据初始化表达式自动推范围循环提供了一种简洁的语法遍历容器或统一了初始化语法,通过花括号提供了是一个表示空指针的字面量,替代了容auto forC++11{}nullptr导变量类型,减少冗余代码,特别是对于复杂类数组中的所有元素一致的初始化方式这种统一初始化适用于所有易混淆的宏(在许多实现中是整数)for autoelem:NULL0型如迭代器例如,这种语法避免了显式迭代器类型内置类型、数组、容器、自定义类等的类型是,可以隐式转换STL autoit=container{...}STL nullptrstd::nullptr_t替代了管理,减少了错误使用引用可以修改元素,初始化列表还提供了窄化检查,防止可能的数据为任何指针类型使用而非或可container.begin std::vector::iteratornullptr0NULL可以与引用、指否则会创建元素副本范围循环要求容器支丢失,如会导致编译错误,而以避免函数重载歧义,如和it=container.begin autofor int x{
1.5}intxvoid fintvoid针和结合使用,但推导规则可能导致意外持和方法或者有对应的全局函数则允许截断允许函,使代码更安全、更明确const beginend=
1.5std::initializer_list fchar*结果,如始终推导为值类型而非引用数和构造函数接受可变长度的同类型参数auto右值引用与移动语义右值引用是一种新的引用类型,绑定到T即将销毁的临时对象移动语义允许窃取即将销毁对象的资源,避免不必要的复制,极大提高了性能移动构造函数和移动赋值运算符用接受右值引用参数,实现资源转移std::move将左值转换为右值引用,允许对命名对象使用移动语义,但之后该对象处于有效但未指定的状态是标准的一次重大更新,引入了许多现代化特性,显著改进了语言的易用性、表达能力和性能除了上述特性外,还引入了常量表达式、统一的函数声明语法(后置返回C++11C++C++11constexpr类型)、强类型枚举、委托构造函数、默认和删除函数等众多改进enum class=default/=delete新特性
(二)C++11/14表达式语法与捕获与变参模板lambda std::function std::bind表达式是一种定义匿名函数对象的简洁方是一个通用的函数封装,可以存变参模板允许模板接受任意数量和类型的参数,使lambda std::function式,格式为储、复制和调用任何可调用对象函数、函数指用模板参数包语法变参模板通[capture]parameters-...template捕获列表决针、成员函数指针、函数对象或表达式常与递归展开配合使用,处理参数包中的每个参return_type{body}[capture]lambda定了如何访问外部变量不捕获任何变量;它为可调用对象提供了类型擦除和统一接口,如数这个特性极大增强了的泛型编程能力,使[][=]C++按值捕获所有变量;按引用捕获所有变量;创建了一个将参数绑定得编写类型安全的可变参数函数变得可能,如[]std::function std::bind捕获特定变量可以捕获指到可调用对象的新可调用对象,允许部分应用函数、和[x,y]Lambda thisstd::make_shared std::make_unique针,允许使用初始化捕获参数、重新排列参数或保存对象状态虽然的实现都依赖于变参模板C++14[x=std::tuple极大简化了与算法库的在很多情况下取代了,但在特std::movey]Lambda lambdabind bind交互,使代码更加函数式和声明式定场景下仍然有用常量表达式线程库介绍constexpr关键字表明表达式或函数可以在编译时求值,允许更多计算在编译期引入了标准线程库,包括线程管理、互斥量constexpr C++11std::thread完成,提高运行时性能函数在编译时使用常量参数调用时保证编译、锁、条件变量和原constexpr std::mutex std::lock_guard std::condition_variable时求值,但也可以在运行时使用中函数限制较严(只能有一子操作等组件这提供了可移植的并发编程支持,无需依赖平台C++11constexpr std::atomic个语句),大幅放宽了这些限制,允许使用局部变量、循环和条特定线程库还包括高级同步原语如和,用于异步return C++14API std::future std::promise件语句常量表达式在模板元编程、嵌入式系统和性能敏感代码中特别有用结果传递改进了原子智能指针和互斥量,添加了并行算法支C++14C++17持,进一步增强了并发编程能力和带来的现代化特性极大地改变了编程风格,使代码更加简洁、表达力更强、更安全、更高效这些特性不仅提高了开发效率,也减少了常见错误,同时保持C++11C++14C++了的高性能传统熟练掌握这些新特性是现代程序员的必备技能,它们可以用于解决各种编程挑战,从低级系统编程到高级应用开发C++C++文件操作1文本文件读写通过头文件提供了文件流类,用于读写文本文件用于读取,用于写入,同时支C++fstream ifstreamofstream fstream持读写打开文件需指定路径和模式文本模式下,读写使用流操作符std::ifstream filedata.txt,std::ios::in file读取,写入函数用于读取整行文本文件操作完成后应调用关闭文件,但流对象析variable filedata getlineclose构时会自动关闭良好实践是使用模式管理文件流的生命周期RAII2二进制文件操作二进制模式允许精确读写字节,不进行任何转换使用和方法操作二进制数据std::ios::binary readwrite和二进制模式特别适合存储结构化数据、图像或其他非文file.readreinterpret_castdata,sizeofdata file.write...本信息处理二进制文件时需注意平台差异(如字节序、对齐)和类型大小变化,特别是包含指针的结构体不应直接写入序列化库可以解决这些问题,提供更安全的二进制数据处理3文件流状态检查文件操作可能因各种原因失败,如文件不存在、权限问题或磁盘已满提供了几种检查流状态的方法返回流是否C++good正常;检查是否到达文件末尾;检查是否发生可恢复错误;检查是否发生严重错误流对象可以在布尔上下文eof failbad中使用,如检查流是否可用错误处理应该是文件操作的标准部分,确保程序能够优雅地处理异常情况iffile4随机访问与文件指针文件流支持通过文件指针(位置指示器)进行随机访问方法移动读写指针到指定位置seekg/seekp/file.seekgoffset,,可以是(文件开头)、(当前位置)或(文件末尾)origin originstd::ios::beg std::ios::cur std::ios::end tellg/tellp返回当前读写位置随机访问在处理结构化文件、数据库或需要非顺序访问的应用中特别有用注意,文本文件中的换行符/处理可能导致位置计算复杂化,随机访问通常在二进制模式下更可预测文件操作是大多数程序的基本需求,用于持久化数据、配置信息、日志记录等的流式提供了一个统一的接口处理各种输入输出操C++I/O作,文件流继承了和使用的相同机制,使用起来自然而熟悉现代开发中,常将文件操作封装在资源管理类中,利用确保cin coutC++RAII正确的资源释放,并使用异常处理机制应对错误情况程序设计实践代码组织与工程结构编码规范与最佳实践性能优化技巧调试与测试方法良好的代码组织对于大型项目至关重要典型一致的编码规范提高了代码可读性和可维护性能优化应遵循先测量,后优化原则全面的测试确保代码质量和可靠性单元测试C++的项目结构包括源代码目录、头文性常见规范包括命名约定(如或使用性能分析工具如、或框架如或用于测试独立C++src camelCaseValgrind perfIntel GoogleTest Catch2件目录、测试目录、构建脚)、缩进风格、注释规范和文件组识别瓶颈常见优化技术包括避免不组件;集成测试验证组件交互;系统测试检查include testsnake_case VTune本、文档和资源文件应用接口与实现分离织遵循原则设计类单一责任、开放必要的复制和内存分配;利用移动语义转移资整个应用行为测试驱动开发先写测试SOLID TDD原则,将类的声明放在头文件中,定义放在源封闭、里氏替换、接口隔离和依赖反转优先源;正确使用值传递、引用传递和移动语义;再实现功能,有助于设计清晰接口和可测试代文件中使用命名空间避免名称冲突,遵循一使用管理资源,避免原始指针和显式内存预先保留容器容量避免频繁重新分配;选择适码调试工具如、或RAII GDBLLDB Visual致的文件命名约定采用模块化设计,将功能管理尽量使用修饰不变量,使用引用合操作模式的数据结构;注意数据局部性和缓调试器帮助定位问题;内存检查工具如const Studio相关的组件组织成逻辑单元构建系统如避免不必要的复制工具如可存友好设计;考虑并行化计算密集型任务编或clang-format ValgrindsMemcheck AddressSanitizer或可以管理依赖关系和跨平台以自动格式化代码,和译器优化选项如或也能显著提升性检测内存错误断言、日志和错误处理机制对CMake Mesonclang-tidy cppcheck-O2-O3构建过程可以检测潜在问题能,但可能增加编译时间和可执行文件大小于开发和诊断同样重要自动化流程可CI/CD以在每次代码更改时运行测试,确保持续质量成功的项目需要平衡语言的强大功能与其复杂性良好的设计减少了复杂性,提高了代码质量和团队生产力现代注重安全性和可维护性,鼓励使用标准库、和智能指针等安全实C++C++RAII践,减少常见错误如内存泄漏和越界访问持续学习和改进是掌握的关键,随着语言标准和最佳实践的演进,保持知识更新对于编写高质量代码至关重要C++学习路径与资源推荐书籍与在线教程学习资源丰富多样入门者推荐《》或《程序设计原理与实践》,这些书籍系统介绍基础知识进阶读物包括C++C++Primer C++Bjarne的《程序设计语言》和的《》系列,深入剖析语言特性和最佳实践在线资源方面,Stroustrup C++Scott MeyersEffective C++提供全面准确的语言参考;提供结构化教程;、和等平台提供互动视频课cppreference.com learncpp.com PluralsightUdemy Coursera程上的优质开源项目也是学习实际代码的宝贵资源GitHub进阶学习方向掌握基础后,可以向多个方向深入设计模式学习如何解决常见软件设计问题,推荐《设计模式可复用面向对象软件的基础》和《现代C++设计》;并发编程处理多线程和同步问题,推荐《并发编程实战》;模板元编程探索编译时编程技术,适合喜欢挑战的开发者;性能C++C++优化学习如何编写高效代码,推荐《》和《优化》;操作系统嵌入式编程应用构建底层系统;游戏开发结合图形编程Efficient C++C++/C++和性能优化技术实践项目推荐实际项目是巩固知识的最佳方式初学者可以从简单项目开始文本编辑器、简单游戏(如贪吃蛇、俄罗斯方块)、计算器应用或文件管理工具中级项目包括数据库系统、解析器、简单的渲染器或网络聊天应用高级挑战可以尝试开发编译器或解释器、游戏引擎HTML3D组件、嵌入式系统或分布式应用参与开源项目贡献也是宝贵的学习经验,可以从修复简单或改进文档开始每个项目都应关注不同的bug特性和编程技术C++C++标准发展动态标准持续演进,了解新特性对现代开发至关重要带来了革命性变化,引入移动语义、、智能指针等;提供C++C++C++11lambda C++14了增量改进;加入了文件系统库、并行算法和结构化绑定;引入了模块、协程、概念和范围了解未来发展方向可关注C++17C++20ISO委员会网站、会议录像和著名博客如的标准更新通常每三年一次,保持关注有助于采用最新C++CppCon C++Herb SutterSutters Mill的语言改进和最佳实践学习是一个持续过程,语言的广度和深度意味着总有新东西可学建立坚实的基础知识,然后根据兴趣和职业需求专注特定领域是有效的策略平衡理C++论学习和实际编码至关重要;通过实际项目应用所学知识可以加深理解并发现知识盲点加入社区如的、或本地用户组Reddit r/cpp StackOverflow C++可以获取支持和洞见最重要的是保持好奇心和解决问题的热情,这是成为优秀程序员的关键品质C++。
个人认证
优秀文档
获得点赞 0