还剩48页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
编程入门C++欢迎来到《编程入门》课程,这是一门专为编程新手设计的全面指南通C++过本课程,您将系统地学习编程的基础知识和实用技巧,从简单的语法到C++复杂的面向对象概念本课程包含个精心设计的主题,涵盖了从环境配置、基础语法到高级应用50的全部内容每个主题都配有实例代码和练习,帮助您巩固所学知识,建立编程思维无论您是完全的编程新手,还是希望转向的其他语言程序员,本课程都将C++为您提供清晰的学习路径和丰富的实践机会准备好开始您的编程之旅了C++吗?课程概述明确学习目标本课程旨在帮助初学者全面掌握编程基础知识,建立良好的编程习惯和C++思维方式课程内容从基础语法逐步推进到面向对象编程和标准库应用搭建编程环境您将学习如何在各种操作系统上安装和配置开发环境,熟悉主流编译器C++和集成开发环境的使用方法,为编程实践打下基础循序渐进学习从基本语法到高级特性,课程内容循序渐进,确保您能够系统地建立知识体系,每一步都有坚实的基础丰富实践练习每个主题都配有针对性的编程练习和小项目,帮助您将理论知识转化为实际编程能力,巩固所学内容简介C++起源与发展C++由丹麦计算机科学家Bjarne Stroustrup于1983年创建,最初称为带类的C它是C语言的扩展,增加了面向对象编程的功能,同时保持了C语言的高效性语言比较与Java和Python等高级语言相比,C++提供了更接近硬件的控制能力;与C语言相比,C++增加了面向对象编程和泛型编程的支持,提高了代码复用性和抽象能力应用领域C++广泛应用于性能要求高的领域,如游戏开发(Unity、Unreal引擎)、系统软件(操作系统、数据库)、嵌入式系统和高性能计算等领域优势与特点C++结合了高级语言的抽象能力和低级语言的执行效率,提供了强大的内存管理控制和丰富的语言特性,支持多种编程范式开发环境配置Visual StudioCLion Code::Blocks微软出品的功能强大的JetBrains开发的跨平台开源、跨平台的C/C++IDE,对Windows平台IDE,提供智能代码补IDE,轻量级但功能齐支持极佳,集成了编辑全、重构工具和集成调试全,支持多种编译器适器、编译器、调试器和图器适合在Linux、合资源有限的环境,初学形化界面设计工具社区macOS和Windows上使者上手较为简单版对个人和小型团队免费用,学生可申请免费许可使用证GCC/Clang/MSVC主流C++编译器,GCC适用于Linux和MinGW环境,Clang提供友好的错误信息,MSVC与VisualStudio集成选择合适的编译器对开发效率有显著影响基本语法结构头文件引入#include指令用于引入库文件命名空间using namespace std;声明使用标准命名空间函数main程序执行的入口点,返回整型值注释规范单行//和多行/**/注释方式C++程序的基本结构由几个关键部分组成首先是头文件引入部分,通过#include指令引入需要的库文件例如,#include iostream引入输入输出流库在C++中,命名空间用于组织代码并避免名称冲突标准库的所有组件都在std命名空间中main函数是程序的执行入口,必须返回一个整型值,通常0表示程序正常结束程序中的注释可以使用//进行单行注释,或使用/**/进行多行注释,对代码进行解释和说明数据类型概述数据类型内存占用取值范围用途int4字节-2^31~2^31-1整数值存储float4字节±
3.4e±38单精度浮点数double8字节±
1.7e±308双精度浮点数char1字节-128~127字符存储bool1字节true/false逻辑值存储C++提供了丰富的基本数据类型,用于存储不同种类的数据整型int用于存储整数值,常占用4字节内存;浮点型包括float4字节和double8字节,用于存储带小数点的数值,其中double提供更高的精度;字符型char占用1字节,用于存储单个字符;布尔型bool用于存储真true或假false的逻辑值C++支持类型转换机制,包括隐式转换和显式转换隐式转换在不同类型的操作数进行运算时自动发生,而显式转换通过cast操作符明确指定sizeof运算符可用于获取数据类型或变量的内存占用大小,这在内存管理和数据结构设计中非常有用变量与常量变量声明与初始化命名规则与最佳实践常量定义变量是计算机程序中用于存储数据的命变量名可以包含字母、数字和下划线,常量是程序执行过程中不会改变的值名内存位置在C++中,变量必须先声明但必须以字母或下划线开头,不能使用在C++中,可以使用const关键字声明常后使用,可以在声明时进行初始化,也C++关键字推荐使用驼峰命名法或下划量常量必须在声明时初始化,之后不可以先声明后赋值线分隔的命名风格,名称应具有描述能修改其值性int age=25;//声明const doublePI=
3.14159;驼峰命名法•:studentAge并初始化const intMAX_STUDENTS=100;下划线分隔•:student_agedouble price;//仅声明price=
19.99;//赋值基本输入输出库iostreamC++标准库提供了iostream头文件,包含输入输出流的基本功能cin是标准输入流对象,cout是标准输出流对象,它们是iostream库中的基本组件#include iostreamusingnamespace std;标准输出cout控制台输出用于向屏幕输出数据插入运算符用于将数据插入到输出流中可以连续使用多个插入运算符输出多个值cout你好,世界!endl;cout年龄:25endl;标准输入cin控制台输入用于从键盘读取用户输入提取运算符用于从输入流获取数据并存储到变量中cin会自动根据变量类型处理输入数据int age;cout请输入年龄:;cinage;运算符一算术运算符基本算术运算符自增与自减运算符复合赋值运算符C++提供了基本的算术运算符用于数值计自增++和自减--运算符用于将变量的复合赋值运算符将算术运算和赋值合并在算值加1或减1一起加法前缀形式先增加变量值,再使等同于•+:a+b•++a•+=:a+=b a=a+b用新值减法等同于•-:a-b•-=:a-=b a=a-b后缀形式先使用当前值,再增乘法•a++等同于•*:a*b•*=:a*=b a=a*b加变量值除法等同于•/:a/b•/=:a/=b a=a/b取模求余数,仅用于整数等同于•%:a%b•%=:a%=b a=a%b运算符二关系与逻辑运算符关系运算符逻辑运算符关系运算符用于比较两个值之间的关系,返回布尔类型结果逻辑运算符用于组合多个条件表达式或true false与•:expr1expr2等于•==:a==b或•||:expr1||expr2不等于•!=:a!=b非•!:!expr大于•:ab这些运算符遵循短路求值原则,例如在中,如果为ab a小于•:ab假,则不会被求值;在中,如果为真,则不会被求b a||b ab大于等于•=:a=b值小于等于•=:a=b在中,关系和逻辑运算符的正确应用对于条件判断和流程控制至关重要关系运算符的优先级低于算术运算符,但高于赋值运算C++符逻辑非具有较高的优先级,逻辑与优先级高于逻辑或在复杂表达式中,建议使用括号明确表达式的求值顺序,提高!||代码可读性运算符三位运算符位与操作位或操作位异或操作|^位与运算符对两个操作数的每一位执行逻辑位或运算符对两个操作数的每一位执行逻辑位异或运算符对两个操作数的每一位执行逻与操作,只有当对应位都为1时,结果位才或操作,当对应位任一为1时,结果位为1,辑异或操作,当对应位值不同时,结果位为为,否则为常用于掩码操作,隔离特定否则为常用于设置特定位的值,相同时为常用于切换特定位的状态10010位位运算在处理硬件级别的操作、优化性能和实现特定算法时非常有用左移和右移运算符分别将位模式向左或向右移动指定的位数,实际上相当于乘以或除以的幂位求反运算符对操作数的每一位取反这些位运算符提供了一种高效操作二进制数据的方式,在2~需要直接与二进制位交互的场景,如图形处理、加密算法和压缩算法中广泛应用控制流一条件语句简单语句if当条件为真时,执行指定的代码块如果条件为假,则跳过该代码块if score=60{cout通过考试endl;}语句if-else当条件为真时,执行if块内的代码;当条件为假时,执行else块内的代码if age=18{cout成年人endl;}else{cout未成年人endl;}嵌套语句if在if或else语句内部再包含if-else结构,用于处理多层次的条件判断if score=90{cout优秀endl;}else ifscore=80{cout良好endl;}else ifscore=60{cout及格endl;}else{cout不及格endl;}条件运算符:条件表达式的简写形式,也称为三元运算符//条件真时的值:假时的值string result=score=60通过:不通过;控制流二语句switch基本语法结构switch语句根据表达式的值选择执行路径标签与case breakcase标签标识可能的值,break阻止执行流继续到下一个case分支default当表达式值不匹配任何case时执行default分支switch语句是一种多路分支语句,它根据一个整型表达式的值选择执行不同的代码块相比于多个if-else语句,switch语句在处理多条件分支时代码更加清晰和高效每个case后的break语句非常重要,它会终止switch结构的执行如果省略break,程序会继续执行下一个case,产生贯穿效应,这有时是有意为之,但更多情况下是编程错误switch语句的局限性在于,表达式必须是整型或枚举类型,并且case标签必须是常量表达式尽管存在这些限制,switch语句在特定场景下仍然是条件分支的最佳选择控制流三循环结构循环循环while do-while先测试条件,如果条件为真则执行循环先执行循环体,然后测试条件,如果条件体,然后再次测试条件,直到条件为假为真则继续循环保证循环体至少执行一2适用于事先不知道循环次数的情况次循环控制循环forbreak语句用于提前退出循环,continue在循环开始时初始化变量,设定循环条语句用于跳过当前迭代并进入下一次迭件,并提供迭代表达式结构紧凑,适用代于已知循环次数的情况循环结构是编程中的基本控制流,允许重复执行代码块提供了三种主要的循环结构、和循环,每种都有其适用场C++while do-while for景循环适合条件驱动的场景,适合需要至少执行一次的场景,循环则适合计数型循环和语句提供了while do-while forbreak continue更精细的循环控制,使程序能够响应特定条件中断或跳过处理循环结构是解决重复性任务的强大工具,但使用不当可能导致无限循环或效率低下数组基础142元素索引内存连续性维度类型数组索引从0开始,数组名代表首元素地址数组在内存中连续存储,便于随机访问C++支持一维数组和多维数组的声明数组是中最基本的复合数据类型之一,用于存储相同类型的多个元素数组声明时必须指定其大小,或通过初始化列表隐式确定例如C++int scores
[5];//声明一个包含5个整数的数组int values[]={10,20,30,40,50};//声明并初始化访问数组元素通过索引实现,索引从开始例如,表示数组的第一个元素数组边界检查是程序员的责任,不会自动检查越界访0scores
[0]C++问,这可能导致严重的运行时错误多维数组可以用来表示表格或矩阵数据,例如int matrix
[3]
[4];//3行4列的二维数组在实际应用中,了解数组的内存布局和正确处理数组边界对编写高效、安全的代码至关重要字符串处理风格字符串类C std::string风格字符串本质上是以空字符结尾的字符数组这种表标准库提供的类提供了更安全、更灵活的字符串处理C\0C++string示方法继承自C语言,在C++中仍然支持,但操作不如标准库字能力它会自动管理内存,支持字符串连接、查找、替换等操符串类方便作char greeting
[6]={H,e,l,l,o,#include string\0};string message=你好世界;char shortcut[]=Hello;//自动添加\0string name=C++;string greeting=message+,+name;风格字符串的操作需要使用库中的函数,如、C strlen、等这些函数不检查边界,容易导致缓冲strcpy strcmp区溢出问题string类提供了丰富的成员函数,如length、substr、、等,使字符串操作更加直观和安全find replacestring对象可以像普通变量一样使用,不需要担心内存管理问题函数基础函数声明函数定义函数声明指定函数名称、返回类型和参数列函数定义包含函数的具体实现代码它包括表,让编译器知道函数的存在和使用方式函数头与声明相同和函数体包含在花括号通常放在程序开头或头文件中内的代码返回值函数调用函数通过return语句返回结果返回类型必通过函数名和参数列表调用函数,程序执行须与函数声明中的返回类型兼容void函数转到函数定义处,执行完后返回调用点继续不返回值执行函数是程序的基本构建块,它封装了一段可重用的代码,用于执行特定任务通过将复杂问题分解为小的、管理的函数,可以提高代码的可读C++性、可维护性和可重用性函数的作用域是指变量的可见范围局部变量在函数内部声明,只在函数内部可见,函数结束后被销毁全局变量在所有函数外部声明,在整个程序中可见了解作用域和生命周期对有效管理程序资源和避免名称冲突至关重要参数传递机制值传递函数接收参数值的副本,原始变量不受影响适用于简单数据类型,操作不影响调用者void incrementint num{num++;//不影响原变量}引用传递函数接收参数的引用,可直接修改原始变量高效且避免复制,适合大型对象void incrementint num{num++;//修改原变量}指针传递函数接收指向原始变量的指针,通过解引用修改原值显式表明修改意图void incrementint*num{*num++;//修改原变量}选择合适的参数传递机制对函数设计和程序性能有重要影响值传递创建参数的完整副本,适合小型数据,但对大型对象可能导致性能问题引用传递和指针传递都避免了复制,提高了效率,但使用不当可能导致意外的副作用对于不需要修改的大型对象,可使用const引用传递,既保证效率又防止意外修改在现代C++中,引用传递通常优于指针传递,因为它语法更简洁且不允许空引用函数重载函数重载概念允许同名函数具有不同参数列表参数区分规则2参数数量、类型或顺序必须不同重载解析规则编译器根据调用参数选择最匹配的函数实际应用4常用于实现同一操作对不同数据类型的处理函数重载是C++支持的一种多态形式,允许多个同名函数执行相似但不完全相同的任务当调用重载函数时,编译器根据参数的数量、类型和顺序决定调用哪个函数版本,这个过程称为重载解析重载函数必须在参数列表上有所区别,仅仅是返回类型不同不足以构成重载函数重载的一个典型应用是提供同一功能对不同数据类型的处理,如标准库中的abs函数可以处理整数、浮点数等不同类型重载增强了代码的可读性和一致性,使调用者不必记住多个不同的函数名合理使用函数重载有助于设计出更直观、易用的接口默认参数与内联函数默认参数设置内联函数C++允许为函数参数指定默认值,如果调用时未提供该参数,则使用默认内联函数使用inline关键字声明,建议编译器在调用点展开函数代码,而不值默认参数必须从右向左指定,不能跳过中间参数是执行普通的函数调用这可以减少函数调用开销,提高执行效率//声明带默认参数的函数//内联函数声明与定义void printMessagestringmsg,int count=1;inline intmaxint a,int b{return aba:b;//函数定义}void printMessagestringmsg,int count{for inti=0;icount;i++{//调用内联函数coutmsgendl;int larger=max5,10;//编译器可能将其展开为:}//int larger=5105:}10;//调用方式内联是一种优化请求,编译器可能忽略内联请求复杂函数通常不会被内printMessage你好;//使用默认count=1联内联适合简短、频繁调用的函数printMessage你好,3;//指定count=3递归函数递归原理函数直接或间接调用自身解决问题基本情况递归终止条件,避免无限递归递归步骤3问题分解为更小的子问题递归是一种强大的问题解决方法,特别适合那些可以自然地分解为相似子问题的任务典型的递归函数包括计算阶乘、斐波那契数列和树形结构遍历例如,阶乘函数可以递归定义为int factorialintn{//基本情况if n=1return1;//递归步骤return n*factorialn-1;}递归虽然概念上简洁,但可能导致性能问题每次递归调用都会创建新的函数栈帧,消耗内存并增加执行开销对于深度递归,可能导致栈溢出尾递归是一种特殊形式,函数的最后一个操作是递归调用,一些编译器可以优化尾递归,将其转换为迭代形式,减少栈使用在实际应用中,需要根据问题特性和性能需求权衡使用递归还是迭代方法指针基础指针是中最强大也最复杂的概念之一,它存储内存地址而非直接值声明指针使用星号,如表示一个指向整数的指针指针C++*int*ptr;初始化时应该分配一个有效地址或,未初始化的指针野指针极其危险nullptr解引用操作符用于访问指针指向的值,如将值存储到指向的内存位置指针算术运算允许我们对指针进行加减操作,特别**ptr=10;10ptr适用于数组处理例如,指向下一个元素,增加的字节数取决于指针类型ptr+1指针提供了对内存的直接访问能力,使能够实现底层系统编程和高效数据处理然而,指针使用不当会导致难以调试的问题,如内存泄C++露、缓冲区溢出和悬空指针掌握指针概念是成为熟练程序员的关键一步C++指针与数组数组名作为指针指针遍历数组在大多数表达式中,数组名会自动转换为指向其第一个元素的指针这种转换是使用指针遍历数组通常比索引遍历更高效,特别是在优化的编译器中指针算术使C++中数组和指针紧密关系的基础我们能够直接移动到下一个元素int numbers
[5]={10,20,30,40,50};int numbers
[5]={10,20,30,40,50};int*ptr=numbers;//ptr指向numbers
[0]int*end=numbers+5;cout*ptr;//输出10for int*p=numbers;pend;p++{cout*ptr+2;//输出30numbers
[2]cout*p;//输出数组元素}指针与多维数组的结合需要更复杂的理解二维数组可以看作是数组的数组,其名称会转换为指向包含n个元素的数组的指针例如int matrix
[3]
[4];int*p
[4]=matrix;//p是指向含4个int的数组的指针在函数调用中,当数组作为参数传递时,实际上传递的是指向数组第一个元素的指针,而不是整个数组的副本这就是为什么函数内部修改数组元素会影响原始数组这种机制提高了效率,但也要求程序员对数组大小的管理更加小心动态内存管理内存分配使用new运算符在堆上动态分配内存new返回指向分配内存的指针,失败时抛出std::bad_alloc异常//分配单个整数int*p=new int;*p=10;//分配并初始化int*q=new int20;//分配数组int*arr=new int
[5];内存释放使用delete运算符释放通过new分配的内存未释放的内存会导致内存泄漏,应确保每个new都有对应的delete//释放单个对象delete p;//释放数组delete[]arr;智能指针C++11引入了智能指针,自动管理动态内存,避免常见的内存管理错误主要包括unique_ptr、shared_ptr和weak_ptr#include memory//独占所有权std::unique_ptrint upnew int30;//共享所有权std::shared_ptrint sp=std::make_sharedint40;引用类型引用概念引用指针常量引用vs引用是一个变量的别名,提供了访问现有变量的另一引用提供了与指针类似的间接访问能力,但语法更简常量引用const引用是一种特殊引用,它引用的对种方式与指针不同,引用在创建时必须初始化,并洁,使用更安全引用没有空引用问题,必须总是引象不能通过该引用修改常量引用通常用于函数参且一旦绑定到一个变量,就不能改变绑定对象用一个有效对象引用通常用于函数参数和返回值数,避免不必要的复制同时保护原始数据不被修改•引用必须初始化,指针可以稍后初始化int x=10;void printVectorconstvector vec{•引用不能改变引用对象,指针可以改变指向int rx=x;//rx是x的引用//vec不能被修改•没有空引用概念,而有空指针rx=20;//修改rx也修改x forconst intval:vec{coutx;//输出20•引用使用更简单,直接用变量名访问coutval;}}结构体结构体定义与使用结构体数组结构体作为函数参数结构体struct是一种用户定义的数据类型,允许将不同类型的数据项组合在一可以创建结构体类型的数组,存储多个相同结构的数据记录这在处理同类数据结构体可以作为参数传递给函数,也可以作为函数的返回值传递大型结构体个单元中结构体声明定义了一个新类型,可用于创建该类型的变量集合时非常有用,如学生名单、产品目录等时,通常使用引用或指针以避免不必要的复制,提高效率//定义结构体//创建结构体数组//按值传递复制整个结构体struct Student{Student class101
[30];void displayStudentStudent s{string name;couts.name,s.idendl;int id;//初始化结构体数组元素}float gpa;class101
[0]={张三,10001,
3.5};};class101
[1]={李四,10002,
3.7};//按引用传递不复制,可修改原结构体void updateGPAStudents,float newGPA{//创建结构体变量//访问结构体数组元素的成员s.gpa=newGPA;Student alice;coutclass101
[0].name;//输出张三}alice.name=李华;alice.id=10001;//返回结构体alice.gpa=
3.8;Student createStudentstring name,int id{Students={name,id,
0.0};return s;}枚举类型传统枚举强类型枚举enum enum class传统枚举在C++中定义一组命名的整型常量枚举成员在其作用域内是可见的,默认从0开始递C++11引入了强类型枚举enum class或enum struct,提供了更好的类型安全性和作用域控增,也可以显式指定值制强类型枚举的成员只在枚举类型作用域内可见,且不会隐式转换为整数//定义传统枚举//定义强类型枚举enum Color{enumclassTrafficLight{RED,//值为0RED,GREEN,//值为1YELLOW,BLUE,//值为2GREENYELLOW=10,//显式值};PURPLE//值为11};//使用强类型枚举TrafficLight light=TrafficLight::RED;//使用枚举if light==TrafficLight::RED{Color myColor=BLUE;cout红灯停endl;if myColor==BLUE{}cout颜色是蓝色endl;}//需要显式转换为整数int value=static_castlight;传统枚举的问题是成员名直接注入到其作用域,可能导致名称冲突,且可以隐式转换为整数强类型枚举解决了传统枚举的作用域污染和类型安全问题,是现代C++推荐的枚举方式类与对象基础类定义对象创建成员访问类是C++的基本构建块,它定对象是类的实例,表示类定义使用点运算符.访问对象的义了一种新的数据类型,结合的具体实体通过声明类的变成员,或使用箭头运算符-数据和操作这些数据的函数量或使用new创建动态对访问通过指针引用的对象的成类定义包括数据成员属性和象,每个对象有自己的数据成员成员访问受访问控制修饰成员函数方法的声明员副本符限制访问控制访问修饰符public、private、protected控制类成员的可见性和可访问性,实现数据封装和信息隐藏,这是面向对象编程的核心原则类是C++面向对象编程的核心特性,它允许我们创建自定义数据类型,封装数据和功能通过类定义的类型称为抽象数据类型,它描述了对象的属性和行为,而不暴露实现细节类中的数据成员储存对象的状态,而成员函数定义对象的行为类定义了一个蓝图,而对象是根据这个蓝图创建的具体实例每个对象都有自己的数据成员副本,但所有对象共享相同的成员函数代码这种设计促进了代码重用和模块化,是构建复杂软件系统的基础构造函数与析构函数默认构造函数不接受参数或所有参数都有默认值的构造函数如果没有定义任何构造函数,编译器会生成一个默认构造函数class Point{public://默认构造函数Point:x0,y0{}private:int x,y;};参数化构造函数接受一个或多个参数的构造函数,用于创建对象时初始化特定值可以使用初始化列表高效初始化成员变量class Point{public://参数化构造函数Pointint xVal,int yVal:xxVal,yyVal{}private:int x,y;};拷贝构造函数接受同类型对象引用作为参数的构造函数,用于创建现有对象的副本如果未定义,编译器会生成一个执行成员逐个复制的版本class Point{public://拷贝构造函数Pointconst Pointother:xother.x,yother.y{}private:int x,y;};对象封装公有接口私有成员使用关键字声明,可以在类外部访问通过public使用关键字声明,只能在类内部访问这private设计良好的公有接口,控制对私有数据的访问是实现封装的主要机制,保护数据不被外部直接修改保护成员使用关键字声明,只能在类内部和派protected生类中访问提供了一种中间级别的访问控制修改器方法访问器方法用于修改私有数据的公有成员函数,通常命名为setXxx,可以在修改前执行数据验证用于读取私有数据的公有成员函数,通常命名为,可以提供只读访问或添加验证逻辑getXxx封装是面向对象编程的三大核心原则之一其他两个是继承和多态,它通过隐藏对象的内部状态和实现细节,只暴露必要的接口来操作对象封装提供了数据保护和访问控制,防止外部代码直接修改对象的内部状态,从而维护对象的完整性和一致性良好的封装设计可以使类的实现细节与其公共接口分离,允许实现细节在不影响使用者的情况下进行修改这种信息隐藏原则是构建可维护和可扩展软件系统的关键因素,它降低了系统各部分之间的耦合度,增强了代码的模块化和复用性指针this指针概念显式使用的场景this this在C++中,this是一个特殊的隐式指针,指向当前正在执行成员函数的对虽然在大多数情况下this的使用是隐式的,但在某些场景下需要显式使用象它是所有非静态成员函数的隐藏参数,使成员函数能够访问调用它的特this指针定对象•解决成员变量与参数名称冲突•在成员函数中返回当前对象的引用class Counter{•将当前对象作为参数传递给其他函数private:int count;•在模板中区分成员和非成员public:void increment{//this指向调用increment的Counter对象this-count++;//等同于count++}};链式调用通过返回this指针或更常见的是返回*this引用,可以实现方法链式调用,使多个操作能够连续执行,提高代码的可读性和表达能力class StringBuilder{private:string data;public:StringBuilder appendconst string str{data+=str;return*this;//返回当前对象的引用}//链式调用示例//sb.appendHello.append.appendWorld;};静态成员静态成员是属于类而不是对象的成员,所有类的对象共享同一份静态成员静态成员变量只存在一个副本,不管创建了多少个类的实例静态成员函数不与特定对象关联,不能访问非静态成员变量,也没有this指针静态成员变量必须在类外部定义和初始化,通常在实现文件.cpp中//在头文件中声明class Counter{public:static inttotalCount;//声明静态成员变量static voidshowTotal;//声明静态成员函数};//在实现文件中定义和初始化int Counter::totalCount=0;//定义并初始化静态成员变量void Counter::showTotal{cout总计数:totalCountendl;}友元函数与友元类友元概念友元是C++中破除封装的一种受控机制,允许指定的函数或类访问其他类的私有和保护成员友元关系是单向的,不具有传递性友元函数友元函数是在类中声明但定义在类外部的函数,可以访问类的私有和保护成员全局函数、其他类的成员函数都可以成为友元class Box{private:double width;public:Boxdouble w:widthw{}//声明全局函数为友元friend void printWidthconst Box box;};//友元函数定义voidprintWidthconstBoxbox{//可以访问私有成员widthcout宽度:box.widthendl;}友元类友元类的所有成员函数都可以访问原类的私有和保护成员这在需要紧密协作的类之间很有用,但应谨慎使用以维持封装class Box{private:double width;public:Boxdouble w:widthw{}//声明BoxManager为友元类friend class BoxManager;};classBoxManager{public:void adjustWidthBoxbox,double newWidth{//可以访问Box的私有成员box.width=newWidth;}};运算符重载运算符重载概念成员函数全局函数vs运算符重载允许自定义类型的对象使用C++内置运算符如+,-,*,==等,使代码更加直观和自然重运算符可以作为成员函数或全局函数重载成员函数重载要求左操作数是类对象;全局函数重载则允许载后的运算符对于自定义类型有特定的意义,但不能改变运算符的优先级、结合性或参数数量左操作数是其他类型,通常需要声明为友元以访问私有成员class Complex{class Complex{private://类定义同上double real,imag;public://声明全局operator为友元Complexdouble r=0,double i=0friend ostream operatorostream os,:realr,imagi{}const Complex c;};//重载+运算符成员函数Complex operator+const Complexother const{//重载运算符全局函数return Complexreal+other.real,ostreamoperatorostreamos,const Complexc{imag+other.imag;osc.real+c.imagi;}return os;}//使用示例://Complex a1,2,b3,4,c;//使用示例://c=a+b;//调用operator+//Complexc1,2;};//coutc;//调用operator常见的重载运算符包括算术运算符+,-,*,/、比较运算符==,!=,,、赋值运算符=、复合赋值运算符+=,-=、下标运算符[]、函数调用运算符、流插入/提取运算符,等运算符重载是C++强大的特性,但应该谨慎使用,保持语义一致性,避免令人困惑的行为继承基础继承概念创建新类时利用现有类的属性和方法1基类与派生类2基类提供共同特性,派生类添加特殊功能继承与访问控制3继承方式影响派生类对基类成员的访问权限继承类型4公有、私有和保护继承具有不同的访问规则继承是面向对象编程的三大核心原则之一,它允许创建一个新类派生类,基于一个现有类基类,复用其功能并添加新特性继承体现了是一种的关系,如学生是一种人,轿车是一种车辆在C++中,继承通过以下语法实现//基类class Animal{protected:string name;public:Animalconst stringn:namen{}void eat{coutname正在进食endl;}};//派生类class Dog:public Animal{private:string breed;public:Dogconst stringn,conststringb:Animaln,breedb{}void bark{coutname汪汪叫endl;}};C++支持三种继承方式公有继承public、保护继承protected和私有继承private,它们影响派生类如何继承基类的访问权限公有继承是最常用的形式,它保持基类成员的原始访问级别继承是构建类层次结构和实现代码复用的强大机制多态性虚函数与动态绑定对象切片与避免方法运行时编译时多态vs虚函数是C++实现多态性的核心机制通过在基类中使用virtual关键字声明函数,并在派生类当派生类对象赋值给基类对象而非指针或引用时,只有基类部分会被复制,这称为对象切片C++支持两种形式的多态运行时多态通过虚函数和继承实现和编译时多态通过函数重载和中重写override该函数,可以实现运行时多态当通过基类指针或引用调用虚函数时,实际切片后的对象失去了派生类特有的属性和行为,多态性也不再有效避免对象切片的方法是模板实现运行时多态在程序执行期间解析函数调用,而编译时多态在编译阶段解析它们各执行的是对象真实类型的函数版本使用指针或引用操作多态对象有优缺点,适用于不同场景class Shape{Circle circle;//编译时多态函数重载public:Shape shape=circle;//对象切片,只复制Shape部分void printint x{cout整数:xendl;}virtual voiddraw{shape.draw;//调用Shape::draw,而非Circle::draw voidprintstring s{cout字符串:sendl;}cout绘制形状endl;}Shape ref=circle;//引用,没有切片//编译时多态模板virtual~Shape{}//虚析构函数ref.draw;//调用Circle::draw,多态有效template};T maxTa,T b{return aba:b;}Shape*ptr=circle;//指针,没有切片class Circle:public Shape{ptr-draw;//调用Circle::draw,多态有效//调用在编译时解析public:print5;//调用printintvoid drawoverride{//override关键字C++11printhello;//调用printstringcout绘制圆形endl;max10,20;//使用int版本的max}max
3.5,
2.5;//使用double版本的max};//运行时多态示例Shape*shape=new Circle;shape-draw;//输出绘制圆形delete shape;抽象类与接口纯虚函数抽象类纯虚函数是一种特殊的虚函数,在基类中没有实现,只有声明它通过在函数声明末尾添加=0来指定纯虚函数表明派含有至少一个纯虚函数的类称为抽象类抽象类不能被实例化,只能作为其他类的基类抽象类的主要目的是定义接生类必须提供该函数的实现,否则也会成为抽象类口,强制派生类实现特定的功能class Shape{//无法创建抽象类的对象public://Shape shape;//错误!//纯虚函数virtual double area const=0;//派生类必须实现所有纯虚函数virtual double perimeter const=0;class Circle:public Shape{virtual~Shape{}//虚析构函数private:};double radius;public:Circledouble r:radiusr{}doubleareaconst override{return
3.14159*radius*radius;}doubleperimeterconst override{return2*
3.14159*radius;}};//现在可以创建Circle对象Circle circle
5.0;在C++中,接口是一种特殊的抽象类,只包含纯虚函数,没有数据成员和函数实现接口定义了一组操作,但不指定如何实现通过接口,不相关的类可以实现相同的行为,实现多重继承的效果而避免菱形继承问题C++支持多接口实现,一个类可以继承多个抽象类,只要实现了所有纯虚函数这种机制允许组合不同的行为,增强了代码的灵活性和可复用性接口是设计模式和大型软件系统中的重要工具,促进了松耦合和可维护性异常处理块try包含可能引发异常的代码当try块中的代码抛出异常时,程序执行跳转到匹配的catch块try{//可能引发异常的代码int*array=new int
[1000000000];//可能失败//使用array...}catch conststd::bad_alloc e{//处理内存分配失败cerr内存分配失败:e.whatendl;}语句throw用于抛出异常,可以抛出任何类型的值,但通常抛出异常类对象throw后,程序执行立即跳转到匹配的catch块double dividedoublea,double b{if b==0{throw std::runtime_error除数不能为零;}return a/b;}块catch捕获并处理特定类型的异常catch块根据异常类型匹配,可以有多个catch块处理不同类型的异常try{double result=divide10,0;cout结果:resultendl;}catch conststd::runtime_error e{cerr运行时错误:e.whatendl;}catch...{//捕获任何其他类型的异常cerr未知异常endl;}文件操作文件写入文件读取读写模式二进制文件操作ofstream ifstreamfstream用于创建文件并向其写入数据如果文件已用于打开文件并读取其内容可以按行读取同时支持读取和写入操作通过打开模式参通过二进制模式读写原始内存块,适用于非存在,默认会覆盖内容;如果不存在,则创或使用流提取运算符读取特定类型的数据数控制访问方式文本数据如图像、音频等建新文件ifstream inFiledata.txt;fstream filedata.txt,struct Person{char name
[50];#include ifinFile.is_open{ios::in|ios::out|ios::app;int age;};ofstream outFiledata.txt;string line;//ios::in-读取Person person={张三,25};if outFile.is_open{while getlineinFile,//ios::out-写入outFileHello,文件IO!line{//ios::app-追加模式//写入二进制数据endl;coutlineendl;//ios::binary-二进制模式ofstream outBinaryperson.dat,outFile100}ios::binary;
3.14endl;inFile.close;outBinary.writechar*person,outFile.close;}sizeofPerson;}//读取二进制数据Person readPerson;ifstream inBinaryperson.dat,ios::binary;inBinary.readchar*readPerson,sizeofPerson;模板编程基础函数模板1创建通用函数,适用于不同数据类型类模板2定义可参数化的类型,实现类型无关的容器和算法模板特化3为特定类型提供优化或特殊实现模板是C++支持泛型编程的核心机制,允许编写独立于具体数据类型的代码通过模板,可以创建适用于多种数据类型的函数和类,而不必为每种类型编写重复代码编译器在编译时根据模板参数生成特定类型的代码,这被称为模板实例化函数模板的基本语法如下templateT maxTa,T b{return aba:b;}//使用不同类型调用模板函数int maxInt=max10,20;//T被推导为intdouble maxDouble=max
3.5,
2.8;//T被推导为doublestring maxStr=maxstringabc,stringdef;//T被推导为string类模板允许创建参数化的类型,如容器类templateclass Stack{private:vector elements;public:void pushconstT item{elements.push_backitem;}T pop{if elements.empty{throw runtime_error栈为空;}T top=elements.back;elements.pop_back;return top;}};//创建不同类型的栈Stack intStack;//整数栈Stack stringStack;//字符串栈标准模板库概述STL容器一顺序容器STLvector list动态数组,支持快速随机访问,在尾部插入/删除元素效双向链表,支持常数时间在任何位置插入和删除元素,但率高,在中间或头部操作效率低内存连续,增长时可能不支持随机访问内存不连续,元素存储在分散的节点需要重新分配内存和复制元素中,每个节点包含前后指针#include#includevector nums={1,2,3,4,5};list names={张三,李四};nums.push_back6;//在尾部添加names.push_front王五;//在头部添元素加nums
[2]=10;//随机访问auto it=names.begin;for intnum:nums{...}//遍历advanceit,1;//移动迭代器names.insertit,赵六;//在指定位置插入deque双端队列,支持在两端高效插入/删除,也支持随机访问内存不完全连续,使用分段连续存储,兼顾了vector和list的优点#includedeque values;values.push_back
1.5;//在尾部添加values.push_front
2.5;//在头部添加values
[1]=
3.5;//随机访问除了主要的三种顺序容器外,STL还提供了array固定大小数组、forward_list单向链表等容器选择合适的容器应考虑需要执行的操作类型、元素数量、内存限制等因素vector是最常用的容器,适合大多数场景;list适合频繁插入/删除操作;deque适合两端操作频繁的情况不同容器性能特性的理解对于编写高效代码至关重要容器二关联容器STLmap/multimap set/multisetmap存储键值对,键唯一且自动排序;multimap允许重复键内部实现为平衡二叉树通set存储唯一元素,自动排序;multiset允许重复元素同样基于平衡二叉树实现,适用于常是红黑树,保证对数时间的查找、插入和删除需要维护元素顺序的集合操作主要操作红黑树实现查找find、插入insert、删除erase是关联容器的核心操作它们还支持上下界查询关联容器通常基于红黑树实现,这是一种自平衡二叉搜索树,保证Olog n的操作复杂lower_bound/upper_bound和范围迭代度,提供有序遍历和范围查询能力map和set容器的使用示例#include#include//map示例map scores={{张三,95},{李四,88}};scores[王五]=90;//插入新键值对auto it=scores.find李四;//查找if it!=scores.end{coutit-first:it-secondendl;}//set示例set uniqueNums={5,2,8,1,5};//5只会存储一次uniqueNums.insert3;//插入新元素for intnum:uniqueNums{//按序遍历:1,2,3,5,8coutnum;}容器三无序容器STL哈希表原理无序容器类型无序容器基于哈希表实现,提供平均常数时间的查找、插入和删除操作哈希表使用哈希函数将键映射到桶bucket,然后在桶内查找元素C++11引入了四种无序容器良好的哈希函数能够均匀分布元素,减少碰撞,提高性能•unordered_map:存储键值对,键唯一C++标准库为常见类型提供了默认哈希函数,也允许自定义类型通过特化std::hash模板提供哈希函数哈希表的性能受负载因子元素数量/桶•unordered_multimap:允许重复键的键值对数量影响,容器会在需要时自动调整桶数量•unordered_set:存储唯一元素•unordered_multiset:允许重复元素这些容器提供与对应的有序容器类似的接口,但不保证元素顺序它们通常在大数据集上比有序容器更快,特别是在只需要频繁查找而不关心顺序的场景#include#include//unordered_map示例unordered_map scores={{张三,95},{李四,88}};scores[王五]=90;//平均O1复杂度auto it=scores.find李四;//平均O1查找if it!=scores.end{coutit-first:it-secondendl;}//unordered_set示例unordered_set uniqueNums={5,2,8,1,5};//5只会存储一次uniqueNums.insert3;//平均O1插入for intnum:uniqueNums{//遍历顺序不确定coutnum;}//自定义类型需要提供哈希函数和相等操作符struct Person{stringname;int age;bool operator==const Personother const{return name==other.nameage==other.age;}};//特化std::hash模板namespacestd{templatestruct hash{size_t operatorconstPerson pconst{return hashp.name^hashp.age;}};}算法STLSTL算法是一组操作容器元素的通用函数模板,定义在头文件中它们通过迭代器操作元素,实现了容器与算法的分离,使得算法可以应用于任何提供适当迭代器的容器主要算法分类包括非修改序列操作如find、count、修改序列操作如copy、transform、排序和相关操作如sort、merge、数值操作在中,如accumulate算法示例#include#include#includevector nums={5,2,8,1,3};//排序sortnums.begin,nums.end;//升序:1,2,3,5,8sortnums.begin,nums.end,greater;//降序:8,5,3,2,1//查找auto it=findnums.begin,nums.end,3;if it!=nums.end{cout找到元素:*itendl;}//统计int count=count_ifnums.begin,nums.end,[]intn{return n3;};//转换vector squarednums.size;transformnums.begin,nums.end,squared.begin,[]intn{return n*n;};//累加来自int sum=accumulatenums.begin,nums.end,0;迭代器迭代器概念提供遍历容器元素的统一接口迭代器类型2输入、输出、前向、双向、随机访问五种类型迭代器操作3递增、解引用、比较等通用操作迭代器适配器4反向、插入、流迭代器等特殊用途迭代器迭代器是C++STL的核心概念,它作为容器和算法之间的桥梁,提供了访问和遍历集合元素的统一方式每种容器都定义了自己的迭代器类型,但都遵循共同的接口标准,使算法可以操作不同类型的容器C++定义了五种主要的迭代器类型,按照功能递增排序
1.输入迭代器只读,单向,单遍访问(如istream_iterator)
2.输出迭代器只写,单向,单遍访问(如ostream_iterator)
3.前向迭代器可读写,单向,多遍访问(如forward_list迭代器)
4.双向迭代器可读写,双向,多遍访问(如list迭代器)
5.随机访问迭代器可读写,随机访问,多遍访问(如vector迭代器)迭代器使用示例vector nums={1,2,3,4,5};//使用迭代器遍历for vector::iterator it=nums.begin;it!=nums.end;++it{cout*it;//解引用迭代器获取元素}//C++11的范围for循环内部使用迭代器for intnum:nums{coutnum;}//反向迭代器for vector::reverse_iterator rit=nums.rbegin;rit!=nums.rend;++rit{cout*rit;//从后向前遍历}//常量迭代器不允许修改元素for vector::const_iterator cit=nums.cbegin;cit!=nums.cend;++cit{//*cit=10;//错误不能修改cout*cit;}智能指针详解unique_ptr shared_ptr weak_ptr独占所有权的智能指针,一个资源只能有一个unique_ptr拥共享所有权的智能指针,多个shared_ptr可以共同管理同一资弱引用,不参与资源的所有权,不影响引用计数用于打破有不允许复制,但可以移动转移所有权当unique_ptr销源通过引用计数跟踪资源的使用情况,当最后一个shared_ptr的循环引用问题,或者观察资源但不延长其生命周毁时,它所管理的资源也被自动释放shared_ptr销毁时,资源被释放期#include//创建shared_ptr//创建shared_ptrshared_ptr sp1new int30;auto sp=make_shared60;//创建unique_ptr autosp2=make_shared40;//推荐,更高效unique_ptr up1new int10;//创建weak_ptr观察spauto up2=make_unique20;//C++14,推荐//共享所有权weak_ptr wp=sp;shared_ptr sp3=sp2;//sp2和sp3共享资源//移动所有权//检查资源是否存在unique_ptr up3=moveup1;//up1现在为空//查看引用计数if!wp.expired{coutsp
2.use_countendl;//输出2//获取临时shared_ptr使用资源//访问资源shared_ptr temp=wp.lock;cout*up2endl;//输出20//自定义删除器if temp{auto deleter=[]int*p{cout*tempendl;//释放所有权cout删除资源endl;}up
2.reset;//释放资源,up2变为空delete p;}};//用于数组shared_ptr sp4newint50,deleter;unique_ptr arrnewint
[5];arr
[0]=10;//使用数组语法新特性C++11/14/17类型推导auto关键字自动推导变量类型,简化复杂类型声明decltype获取表达式类型,用于泛型编程auto i=42;//intauto p=new double
3.14;//double*auto it=v.begin;//迭代器类型范围循环for简化容器遍历,更简洁、更不易出错支持所有提供begin和end的类型vector nums={1,2,3};for intn:nums{n*=2;//修改元素}移动语义通过右值引用和std::move实现资源转移而非复制,提高性能,减少内存分配string s1=hello;string s2=moves1;//s1内容转移到s2//s1现在是有效但未指定状态表达式Lambda定义匿名函数对象,简化算法使用,支持闭包捕获变量C++14起支持泛型lambdaauto add=[]int a,int b{return a+b;};coutadd3,4;//输出7//捕获变量intx=10;auto addX=[x]int a{return a+x;};编程规范与调试技巧命名约定良好的命名约定提高代码可读性和可维护性变量名应该清晰表达其用途,函数名应该反映其行为类名通常使用名词,方法名使用动词或动词短语常见命名风格包括驼峰命名法camelCase、帕斯卡命名法PascalCase和下划线分隔snake_case一致的命名风格对团队协作尤为重要代码组织良好的代码组织包括合理的文件结构、模块划分和依赖管理遵循单一职责原则,每个类和函数应该只有一个明确的职责头文件.h应包含声明,源文件.cpp包含定义使用命名空间避免名称冲突,使用前向声明减少编译依赖大型项目应考虑使用构建系统如CMake和包管理工具调试技术有效的调试是解决程序问题的关键常用调试工具包括集成开发环境的调试器如Visual Studio调试器、GDB,它们提供断点设置、单步执行、变量监视等功能日志输出是简单但有效的调试方法,可以使用专用日志库提高灵活性断言assert用于验证程序假设,在开发阶段捕获逻辑错误内存检查工具如Valgrind有助于发现内存泄漏和访问错误课程总结与进阶方向核心概念回顾本课程涵盖了C++编程的基础知识,从语法结构、数据类型、控制流到面向对象编程、模板和STL通过系统学习,您已具备使用C++解决各类问题的基本能力,理解了C++的核心特性和设计理念项目实践建议巩固知识的最佳方式是通过项目实践建议从小型项目开始,如简单游戏、文件处理工具或数据结构实现,逐步挑战更复杂的应用,如图形界面程序、网络通信或数据库应用参与开源项目也是提升能力的有效途径学习资源推荐深入学习的优质资源包括《C++Primer》、《Effective C++》系列、《C++标准库》等经典书籍;cppreference.com、isocpp.org等官方文档;GitHub上的C++示例项目和教程;Stack Overflow解答疑问;各类C++会议视频和技术博客进阶学习路线C++进阶方向包括深入理解内存模型和并发编程;掌握现代C++C++11/14/17/20新特性;学习设计模式和架构原则;专注于特定领域如游戏开发、高性能计算、嵌入式系统或图形学;探索C++与其他语言的交互;参与语言标准化工作。
个人认证
优秀文档
获得点赞 0