前言本篇笔记仅整理本人手写代码及对应知识点涵盖名字空间、函数模板、右值引用、extern C、函数名粉碎机制等内容所有内容均来自代码注释不添加多余冗余内容拆解开讲清每个核心规则方便理解记忆。一、名字空间namespace核心解决命名冲突知识点1. 核心作用解决名称标识符可重用的问题实现作用域隔离避免命名冲突比如两个不同的函数/变量同名通过名字空间区分。2. 定义语法namespace 空间名 { ... }在名字空间内部可以定义变量、常量、函数、类、结构体、枚举等还支持嵌套定义名字空间内部再定义名字空间。3. 关键特性同一个名字空间可以重复定义编译器会自动将多个同名名字空间合并但内部成员不能重复定义否则会报重定义错误。4. 访问方式3种重点掌握1直接访问空间名::成员名最常用无需展开精准访问避免冲突2部分展开using 空间名::成员名只引入名字空间中的某个成员引入后可直接使用该成员3全部展开using namespace 空间名引入名字空间中所有成员引入后可直接使用所有成员注意尽量避免容易与全局成员、其他空间成员冲突。5. 展开范围名字空间既可以在函数内部展开也可以在函数外部展开展开后成员的作用域生命周期与展开位置一致外部展开作用域类似全局变量内部展开仅在该函数内有效。对应代码namespace User1 { double PI 3.1416; int add(int a) { return a 100; } namespace std2 { void send1(string title) { cout hi,User1::send1 title endl; } } } namespace User2 { double PI 3.1415926; int add(int a) { return a 10; } } //同一个名字空间可以重复定义空间但成员不能重定义 namespace User1 { void send(string title) { cout hi, title endl; } } //也就是说对于一个名字空间的编译会自动合并到一起。二、extern C 与 extern C控制函数名字粉碎知识点1. extern C 的作用将函数定义在extern C { }语句块中编译器不会对该函数进行名字粉碎让 C 函数可以被 C 语言调用因为 C 语言没有名字粉碎机制。2. extern C 的作用在 .cpp 文件C 环境中将函数定义在extern C { }语句块中编译器会对该函数进行名字粉碎相当于“强制开启 C 名字修饰”可用于在 C 环境中模拟 C 函数的粉碎特性通常用于兼容 C 语言调用 C 函数的特殊场景。补充C 语言无法直接调用 C 中被名字粉碎的函数通过 extern C 取消粉碎后才能正常调用。对应代码保留本人原代码无任何修改//如何不让函数名字粉碎 //使用extern C { }将函数定义到此语句块中即可不进行名字粉碎 extern C int test() { return 10; }; //在c语言中如何让函数具有函数粉碎机制 //在.cpp文件的条件下使用extern c { }将函数定义到此语句块中即可进行名字粉碎 //更通俗的来说是在c语言环境下去编译c语言可使用这个方法。三、右值与右值引用C11 新增可构成函数重载知识点1. 值类别C11 新增将数据分为左值和右值核心区别在于“是否具名、是否可取地址”。1左值具名有变量名、可取地址有自己的存储空间例如普通变量、指针、数组名等2右值不具名、不可取地址没有独立存储空间例如字面常量10、3.14、临时变量、表达式结果ab等。2. 特殊说明三目表达式的结果类型取决于返回值——若返回的全是左值则表达式结果为左值需用左值引用若返回的是右值则表达式结果为右值需用右值引用。3. 左值引用与右值引用对比1左值引用语法数据类型 引用名 左值只能绑定左值常引用const 左值引用可绑定左值、右值视为万能引用2右值引用语法数据类型 引用名 右值只能绑定右值不能绑定左值4. 核心作用右值引用可以构成函数重载编译器会根据引用类型左值/右值匹配对应的函数常用于优化临时变量的拷贝后续进阶会详细补充。对应代码保留本人原代码无任何修改//右值和右值引用右值引用可以构成函数重载 //c11中引入了值类别分为左值和右值 //左值具名由名字可取地址有自己的存储空间如普通变量指针 //右值不具名不可取地址即没有存储空间如字面常量临时变量表达式结果 // 但是如果三目表达式返回的结果全是左值时则这个表达式的结果也是左值要用左值引用。如果是右值则要用右值引用。 //左值引用对左值的引用对象必须严格是右值常引用认为为左值引用。 //右值引用: 对右值的引用 //右值引用的语法数据类型 变量名 右值 // 示例左值引用与右值引用的使用 int a 10; int b 10; // 右值引用绑定右值10字面常量 int c a; // 左值引用绑定左值a普通变量 int r3 10; // 右值引用绑定右值10四、函数模板泛型编程函数重载的延伸知识点1. 核心定义定义时以泛型替代实际的类型在调用时具体化泛型类型实现“一套代码多种类型复用”本质是函数重载的体现每一个泛型具体化都是一个重载函数。2. 定义语法在函数上方声明模板格式为templatetypename|class 泛型名typename 和 class 等价可互换泛型名可自定义常用 T、T1、T2 等。3. 关键特性1可定义多个泛型用逗号分隔例如templateclass T1, class T2, class T32调用方式可自动推导泛型类型根据传入实参的类型也可手动指定泛型类型格式函数名泛型类型1, 泛型类型2(实参)3声明与定义函数模板的声明和定义可以分开但不建议分开容易出现链接错误新手直接将声明和定义写在一起即可。4. 优势替代传统的多类型重载函数如 int add、float add、double add减少代码冗余提高复用性。对应代码// 函数模板: 定义时以泛型替代实际的类型在调用时具体化函数模板的声明和定义是可以分开的但是我们不建议将他们分开。 // 函数模板也是函数重载的体现: 每一个具体化都是函数的重载 // 函数模板语法(函数上方定义模板) templatetypename|class 泛型名 templatetypename T T add(T a, T b) { return a b; } // 函数模板定义泛型时可以同时定义多个泛型使用,逗号分隔 templateclass T1, class T2, class T3 T3 sub(T1 a, T2 b) { return a - b; } #if 0 int add(int a, int b) { return a b; } float add(float a, float b) { return a b; } double add(double a, double b) { return a b; } double sub(short a, int b) { return a - b; } int sub(char a, short b) { return a - b; } #endif // 多泛型函数模板示例 templateclass T1,class T2 T2 add(T1 a, T1 b) { return a * b; }五、主函数测试整合所有知识点可直接上机知识点基于本人手写注释详细解读主函数中整合了前面所有知识点名字空间、右值引用、函数模板的测试逻辑可通过修改#if 0为#if 1开启对应测试块验证每个知识点的效果调用函数模板时可自动推导泛型类型也可手动指定灵活便捷。对应代码int main() { //回顾知识点 //1.inline函数 //2.缺省值 //3.函数重载 //4.函数名粉碎机制 int a 10; int b 10; int c a; int r3 10; cout addint, double (1, 2) endl; int PI 3; //访问名字空间中的成员 //语法 空间成员::成员 cout 精度低的PI User1::PI endl; cout 精度高的PI User2::PI endl; cout PI endl; cout User1::add(10) endl; cout User2::add(10) endl; User1::std2::send1(hello); return 0; }附录本人原版完整代码未做任何修改可直接复制上机#if 1 #includestdio.h #includeassert.h #includestring.h #includestdlib.h #define _CRT_SECURE_NO_WARNINGS #includestring #includeiostream using namespace std; //namespace 名字空间 //作用 解决名称标识符可重用的问题 //namespace 定义语法;namespace 名字 {...} //在namespace 名字空间中可以定义变量常量函数类结构体枚举等 //名字空间可以嵌套即名字空间可以内部再定义一个名字空间 //例如 namespace User1 { double PI 3.1416; int add(int a) { return a 100; } namespace std2 { void send1(string title) { cout hi,User1::send1 title endl; } } } namespace User2 { double PI 3.1415926; int add(int a) { return a 10; } } //同一个名字空间可以重复定义空间但成员不能重定义 namespace User1 { void send(string title) { cout hi, title endl; } } //也就是说对于一个名字空间的编译会自动合并到一起。 //如何使用名字空间(名字空间既可以在函数内部里面展开也可以在函数外部展开) // 在那里展开其展开后的成员的作用域即声明周期就在那里。 //using namespace 空间名称;//是将空间中的所有成员都引入到我们这个此程序中级别和全局变量的地位差不多。 //using 空间名称::成员;//是将空间中的某个成员引入到我们这个此程序中级别同样和全局变量的地位差不多。 //直接引入到此程序后就可以直接访问了。 //但是使用了名字空间要尽量避免在定义一个同名的成员。 //如果我们不使用using namesapce 空间名; //那么我们要使用 空间名::成员名 来访问名字空间里面的变量。 //名字空间的本质 //作用域隔离 //解决命名冲突问题 //如何不让函数名字粉碎 //使用extern C { }将函数定义到此语句块中即可不进行名字粉碎 extern C int test() { return 10; }; //在c语言中如何让函数具有函数粉碎机制 //在.cpp文件的条件下使用extern c { }将函数定义到此语句块中即可进行名字粉碎 //更通俗的来说是在c语言环境下去编译c语言可使用这个方法。 //右值和右值引用右值引用可以构成函数重载 //c11中引入了值类别分为左值和右值 //左值具名由名字可取地址有自己的存储空间如普通变量指针 //右值不具名不可取地址即没有存储空间如字面常量临时变量表达式结果 // 但是如果三目表达式返回的结果全是左值时则这个表达式的结果也是左值要用左值引用。如果是右值则要用右值引用。 //左值引用对左值的引用对象必须严格是右值常引用认为为左值引用。 //右值引用: 对右值的引用 //右值引用的语法数据类型 变量名 右值 // // 函数模板: 定义时以泛型替代实际的类型在调用时具体化函数模板的声明和定义是可以分开的但是我们不建议将他们分开。 // 函数模板也是函数重载的体现: 每一个具体化都是函数的重载 // 函数模板语法(函数上方定义模板) templatetypename|class 泛型名 //templatetypename T //T add(T a, T b) { return a b; } // // //// 函数模板定义泛型时可以同时定义多个泛型使用,逗号分隔 //templateclass T1, class T2, class T3 //T3 sub(T1 a, T2 b) { return a - b; } // //#if 0 //int add(int a, int b) { return a b; } //float add(float a, float b) { return a b; } //double add(double a, double b) { return a b; } // //double sub(short a, int b) { return a - b; } //int sub(char a, short b) { return a - b; } //#endif // //int main() { // // add函数模板的具体化泛型为 int类型 // cout add(1, 2) endl; // // 泛型为 doble // cout add(1.25, 2.4) endl; // // // 调用时可以指定T的类型如float,泛型为 float // cout addfloat(1.35, 5.4) endl; // // // 调用函数模板时需要手动指定泛型的具体化类型名 // double ret1 subshort, int, double(10, 20); // // return 0; //} templateclass T1,class T2 T2 add(T1 a, T1 b) { return a * b; } int main() { //回顾知识点 //1.inline函数 //2.缺省值 //3.函数重载 //4.函数名粉碎机制 int a 10; int b 10; int c a; int r3 10; cout addint, double (1, 2) endl; int PI 3; //访问名字空间中的成员 //语法 空间成员::成员 cout 精度低的PI User1::PI endl; cout 精度高的PI User2::PI endl; cout PI endl; cout User1::add(10) endl; cout User2::add(10) endl; User1::std2::send1(hello); return 0; } #endif