0 初识C++

发布时间:2026/8/27 12:46:20
0 初识C++ C作为一门兼具高性能与抽象能力的通用编程语言自1983年正式命名以来历经多次标准化迭代已成为系统软件、高性能服务端、游戏引擎等邻域的核心开发语言。1 第一个C程序C完全兼容C语言语法因此C风格的程序在C中仍可正常编译运行。但在标准C规范中推荐使用C特有的输入输出机制。编译说明C源文件后缀通常为.cpp在Windows平台使用MSVC编译时编译器会根据后缀自动调用C编译流程在Linux环境下需要使用g而非gcc进行编译。2 命名空间解决标识符冲突的机制在C语言项目中全局作用域内的标识符变量、函数、类极易发生重名冲突尤其是当引入多个第三方库时。C语言缺乏有效的隔离手段。C引入命名空间namespace机制用于创建独立的作用域将不同标识符封装在不同命名空间中。编译器进行名字查找时默认按照当前作用域及其外层作用域进行查找不会自动搜索其他命名空间因此不同命名空间中的同名标识符不会发生冲突。通过作用域解析运算符::或using可以显式访问其他命名空间中的成员。2.1 定义与嵌套命名空间通过namespace关键字定义可包含变量、函数、类型结构体/类及嵌套命名空间。同一命名空间可跨文件合并若在多个文件中定义同名的namespace编译器会自动合并其内容这便于将模块的声明与实现分离。命名空间不影响变量生命周期与局部域自动存储期和全局域静态存储期不同命名空间中的变量具有静态存储期与全局变量一致其声明周期从程序启动延续至结束。2.2 核心特性① 域独立性命名空间域与全局域、局部域相互独立不同域中可定义同名标识符。② 嵌套定义命名空间支持嵌套通过多级作用域::访问嵌套成员。③ 跨文件合并不同源文件中定义的同名空间会被编译合并为同一个逻辑命名空间。这是多文件项目中组织代码的基础机制。④ 作用域分类C中共有四种作用域——局部域、全局域、命名空间域、类域。其中局部域和全局域会影响变量的声明周期而命名空间域和类域仅影响编译器的标识符查找逻辑不改变变量生命周期。2.3 使用方式编译器默认仅在局部域和全局域中查找标识符访问命名空间成员需通过以下三种方式① 指定命名空间访问项目中推荐最安全避免冲突。② 部分成员展开仅展开单个高频使用的成员风险可控。③ 全量展开强烈不推荐头文件或大型项目会导致命名空间污染。在C中访问命名空间中的成员通常有三种通用方式① 可以直接使用完整限定名命名空间:: 成员这种方式最明确不需要任何using。② 可以使用using namespace命名空间;把整个命名空间中的名字引入当前作用域从而省略命名空间前缀但容易产生命名冲突。③ 可以使用using 命名空间::成员;只引入某一指定成员既能简化书写又能减少冲突。工程实践标准库的所有组件均定义在std命名空间中日常练习可使用using namespace std;简化代码但在大型项目中应避免全局展开以防命名污染。标准库std是C最有价值的命名空间但绝不应在头文件中使用using namespace std;否则会污染包含该头文件的源文件导致不可预期的重载冲突。3 标准输入输出流C通过iostream头文件提供标准输入输出功能核心对象包括①std::cinistream类对象负责标准上输入。②std::coutostream类对象负责标准输出。③std::endl函数对象。插入换行符并刷新输出缓冲区。运算符重载为流插入运算符为流提取运算符C复用了C语言的位运算符符号通过运算符重载实现类型自动识别。相比C语言的prinft和scanfC流输出的核心优势在于无需手动指定格式控制符编译器会根据变量类型自动匹配输出逻辑且天然支持类型的输入输出扩展。4 缺省参数函数参数的默认值机制缺省参数允许在函数声明或定义时为参数指定默认值调用时若未提供对应实参则使用默认值。根据缺省参数的覆盖范围可分为① 全缺省参数所有参数均指定默认值。② 半缺省参数部分参数指定默认值。语法规则① 半缺省参数必须从左向右依次连续缺省不允许间隔跳跃。② 函数调用时实参必须从左到右依次传递不允许跳跃传参。③ 声明与定义分离时缺省参数只能在声明中指定。声明与定义分离时的规则当函数声明与定义分开时缺省参数仅能出现在声明中定义处不可重复指定。默认参数属于函数接口而非实现细节其替换发生在编译期的调用点而调用方通常只能看到头文件中的声明、看不到源文件里的定义如果允许在定义中指定默认参数不同源文件可能看到不同的默认值既违反C的“单一定义规则ODR”又会导致链接期无法校验的一致性错误因此C规定默认参数只能在声明中指定且只能指定一次。工程应用缺省参数常用于初始化场景例如栈初始化时若已知数据规模可通过指定缺省参数一次性分配足够内存避免频繁扩容。5 函数重载C允许在同一作用域内定义多个同名函数前提是它们的参数列表不同参数个数、类型或类型顺序不同这成为函数重载。函数重载是C实现静态多态的基础。编译器根据调用时提供的实参类型和数量在编译期决定调用哪个重载版本。当重载函数与缺省参数结合可能引发调用歧义因此设计重载时应避免此类模糊组合。6 内联函数频繁调用小型函数会引入栈帧建立与销毁的开销影响性能。C 语言通过宏函数macro在预处理阶段展开但宏存在诸多缺陷① 缺少类型检查② 容易因运算符优先级问题导致错误③ 无法调试预处理后不可见。C 引入inline关键字建议编译器将函数体在调用点内联展开从而消除调用开销同时保留函数的类型安全和可调试性但在Debug模式下通常不展开以便断点。用inline修饰的函数称为内联函数编译时C编译器会在调用点展开内联函数省去函数调用时的栈帧创建、参数压栈、返回地址保存等开销提升程序执行效率。6.1 内联函数的特性① 编译器建议性inline对编译器仅为建议对于递归函数、代码量较大的函数即使添加inline关键字编译器也可能忽略该建议不进行展开。② 替代宏函数C语言中的宏函数在预处理阶段展开存在语法复杂、易出错、无法调试等问题C引入内联函数作为宏函数的安全替代方案。③ 声明定义不可分离内联函数不建议声明与定义分离到不同文件。内联函数在调用点展开不会生成独立的函数符号若分离到不同文件链接时会因找不到函数地址而报错。通常将内联函数的定义直接放在头文件中供多个源文件包含。6.2 宏函数的问题与内联函数的优势宏正确实现需考虑诸多细节。而内联函数无需额外防范且支持作用域、类型检查和调试应作为替代宏的首选方案。内联函数通常应定义在头文件中因为内联展开需要在翻译单元内看到完整定义。若将声明与定义分离到不同文件链接时找不到函数地址因为未生成符号会引发链接错误。7 nullptr在 C 中传统的NULL本质上通常是整数常量0因此在函数重载场景下func(NULL)更可能匹配func(int)而不是程序员期望的指针版本func(int*)如果想调用指针重载过去往往需要显式强制转换而 C11 引入的nullptr是专门表示“空指针”的类型可以正确匹配指针参数避免0和NULL在整数与指针重载之间产生歧义因此现代 C 应优先使用nullptr表示空指针。