04. 命名空间,函数重载,内联
一.命名空间
C语言中为避免冲突,可能采用
项目名_模块名_名字 的形式,缺点是冗长
C语言中作用域:块,局部(函数),文件,全局
C++有采用命名空间
用法1:using namespace MyNamespace;
namespace MyNamespace { //可以做所有能在全局作用域中做的事 int val = 9;//全局 void f() { } struct MyStruct { int age; double score; }; } using namespace MyNamespace; int main() { val = 100; f(); MyStruct str{ 1,1.1234 }; return 0; } int Foo() { val = 100; f(); MyStruct str{ 1,1.1234 }; return 0; }
如果把using namespace MyNamespace;放在函数内部,则只在该函数内可见。
int main() { using namespace MyNamespace;//把整个命名空间的所有名字导入当前作用域 val = 100; f(); MyStruct str{ 1,1.1234 }; return 0; } int Foo() { //本函数无法使用以下内容,编译出错 val = 100; f(); MyStruct str{ 1,1.1234 }; return 0; }
用法2:
int main() { MyNamespace::val = 100; MyNamespace::f(); MyNamespace::MyStruct str{ 1,1.1234 }; return 0; }
用法3:
using MyNamespace::val;//把MyNamespace的val导入当前作用域 using MyNamespace::f; using MyNamespace::MyStruct; int main() { val = 100; f(); MyStruct str{ 1,1.1234 }; return 0; }
命名空间可以不连续,可以写在多个文件中,例如:
namespace MyNamespace { //可以做所有能在全局作用域中做的事 int val = 9;//全局 void f() { } struct MyStruct { int age; double score; }; } namespace MyNamespace { //可以做所有能在全局作用域中做的事 double foo = 9;//全局 void g() { } }
命名空间可以嵌套:
namespace MyNamespace1 { namespace MyNamespace2 { namespace MyNamespace3 { int age = 100; } } } int main() { MyNamespace1::MyNamespace2::MyNamespace3::age = 0; return 0; }
命名空间可以取别名:
namespace MyNamespace1 { namespace MyNamespace2 { namespace MyNamespace3 { int money = 100; } } } namespace Space = MyNamespace1::MyNamespace2::MyNamespace3;//取个别名,和命名空间原来的名字等价 using namespace Space; int main() { money = 0; return 0; }
using 指示可能会造成冲突:
namespace MyNamespace { //可以做所有能在全局作用域中做的事 double foo = 9;//全局 void f() { } } using namespace MyNamespace; void f() {} int main() { //f();//二义性,编译器可以看见两个f(),不知道调用谁 MyNamespace::f();//明确指定调用MyNamespace的f() ::f();//明确指定调用全局命名空间的f() return 0; }
二.函数重载
C语言中函数不能同名
C++可以重载函数
构成函数重载的条件:
1.作用域相同
2同名函数
3参数列表不同,参数类型、个数、位置任意一个不同均可
3.1参数类型不同
void f(int) {}
void f(double) {}
3.2参数个数不同
void f(int) {}
void f(int, int) {}
3.3参数位置不同
void f(int, double) {}
void f(double, int) {}
4.返回值和调用约定没有效果
C函数编译后基本只保存了函数名,无法重载。
C++处理函数时,会将作用域,函数名,参数列表,返回值,调用约定等都保存起来。
打开开发人员命令行工具,探索vs的名称粉碎,输入undname可解析函数签名,例如:
头文件中如下写,可以实现C调用C++,或者C++调用C,因为都按C的规则编译:
#pragma once #ifdef __cplusplus extern "C" { #endif // __cplusplus int myadd(int a, int b); //其他函数声明 #ifdef __cplusplus } #endif // __cplusplus
函数重载的二义性:
void f(int) {} void f(float) {} void g(int, int arg = 1) {} void g(int) {} int main() { //f(0.1);//error C2668: “f”: 对重载函数的调用不明确 //g(1);//error C2668: “g”: 对重载函数的调用不明确 return 0; }
三.内联inline
有些函数比较简单,调用函数体消耗的时间小于调用准备的时间
内联函数:函数会像宏一样在调用点展开,同时保留函数的类型检查
inline建议编译器展开,是否接受要看编译器。
inline函数具有文件作用域,实现一般放在头文件中。
debug版一般不会内联,即使写了inline关键字
编译选项“内联函数扩展”/Ob0总是不展开,/Ob1写了inline才展开,/Ob2总是尝试展开