命名空间
名字冲突:
一般:工程_模块_函数名
作用域:全局作用域,块作用域,文件作用域,文件作用域
1.using namespace XXX
//using namespace XXX
#include <iostream>
using namespace std;
namespace CR {
//凡是在全局作用域中做的事,命名空间中都可以做
int g_nVal = 999;
void Foo()
{
cout << "CR::Foo" << endl;
}
struct tagTest
{
int m_n;
float m_f;
};
typedef void(*PFN)();
}
1.using namespace CR;//开关,把CR命名空间中的名字拉到当前作用域
int main()
{
{
using namespace CR //2.若在这里使用using,则会报错,只能在这块里面使用CR39里面的属性方法。
}
g_nVal = 0; //调试监视的时候,需要使用 CR::g_nVal
Foo();
tagTest t;
t.m_f = 23.1f;
t.m_n = 2;
using namespace CR;//前面报错,这行后面,才能找到作命名空间。跟定义变量一样,要使用变量前,先定义变量。
PFN pfn = Foo;
pfn();
}
2.使用时 XXX::+()
//xxx::+()
#include <iostream>
using namespace std;
namespace CR {
//凡是在全局作用域中做的事,命名空间中都可以做
int g_nVal = 999;
void Foo()
{
cout << "CR::Foo" << endl;
}
struct tagTest
{
int m_n;
float m_f;
};
typedef void(*PFN)();
}
int main()
{
CR::g_nVal = 0;
CR::Foo();
CR::tagTest t;
t.m_f = 23.1f;
t.m_n = 2;
CR::PFN pfn = Foo;
pfn();
}
3.using XXX::+()
把XXX中的()拉到当前作用域。类似python中的 from xxx import xxxx
注意!如果出现以下场景。
using namespace CR1{
int g_nVal=9;
}
using namespace CR2{
int g_nVal=8;
}
int g_nVal=7;//全局作用域
using namespace CR1;
using namespace CR2;
//需要指明使用对象。
int main()
{
CR1::g_nVal=22;//指明使用CR1中的g_nVal
::g_nVal=21;//使用全局作用域中的g_nVal
}
命名空间可以拆开写,但都表示同一块命名空间。
4.起别名
//CR代码在上方,可以省略
namespace CR1=CR;
usint namespace CR1;
//CR1的用法跟上面一样。
函数重载
在C语言中,没有函数重载,功能相似的函数,参数不同,C语言中通过前缀或者后缀区分。
如下
int Add(int n1, int n)
{
return n1 + n;
}
float float_Add(float n1, float n2)
{
return n1 + n2;
}
float float2_int2_Add(float n1, float n2, int n3, int n4)
{
return n1 + n2 + n3 + n4;
}
在C++中。
int Add(int n1, int n)
{
return n1 + n;
}
float Add(float n1, float n2)
{
return n1 + n2;
}
float Add(float n1, float n2, int n3, int n4)
{
return n1 + n2 + n3 + n4;
}
函数:返回值,调用约定,函数名,参数列表(参数类型,参数的数量,参数的顺序)
参数不同,构成重载
int Add(int n)
{
return 0;
}
int Add(int n, int n1)
{
return 0;
}
int main() {
Add(1);
Add(1, 2);
}
参数类型不同,构成重载
int Add(int n)
{
return 0;
}
int Add(float n)
{
return 0;
}
int main() {
Add(1);
Add(1.4f);
}
参数顺序不同,构成重载
int Add(int n, float r)
{
return 0;
}
int Add(float, int r)
{
return 0;
}
int main() {
Add(1, 2.f);
Add(1.4f, 2);
}
调用约定不同,不构成重载
int __stdcall Add(int n, float r)
{
return 0;
}
int __cdecl Add(float g, int r)
{
return 0;
}
int main() {
Add(1, 2.f);
Add(1.4f, 2);
}
返回值类型不同,不构成重载
float Add(int n)
{
return 0;
}
int Add(float r)
{
return 0;
}
int main() {
Add(1);
Add(1.4f);
}
总结:
构成重载的条件:
1.函数名相同
2.参数列表不同(顺序,类型,个数)
3.返回值和调用约定不考虑
外:
作用域不同,不构成重载
using namespace std;
void Foo(char* p)
{
cout << p << endl;
}
namespace CR
{
void Foo(int n)
{
cout << n << endl;
}
void Test()
{
//Foo("Hello")//作用域内部Foo屏蔽了全局作用域中Foo
}
}
int main()
{
return 0;
}
名称粉碎
//函数重载的原理:名称粉碎 ?Foo@CR@@YAXMHNPAD@Z
namespace CR {
void Foo(float f, int n, double dbl, char* p);
}
int main()
{
CR::Foo(3.2f, 2, 4.5, nullptr);
return 0;
}
使用VS2019自带的控制台
C++兼容C的调用约定
C 前缀 _
c++ @
//函数重载的原理:名称粉碎 ?Foo@CR@@YAXMHNPAD@Z
namespace CR {
void Foo(float f, int n, double dbl, char* p)
{
}
}
extern "C" void Test();//告诉编译器,此函数的名称粉碎规则使用C的而不是C++的
//使用extern "C"后无法进行函数重载
extern "C" void Test1(int n)
{
}
extern "C" void Test2(int n)
{
}
int main()
{
Test();
CR::Foo(3.2f, 2, 4.5, nullptr);
return 0;
}
二义性,歧义
1.要注意函数的调用过程中,注意参数的完美匹配
void Add(int n)
{
}
void Add(float f)
{
}
int main()
{
Add(36.5);
return 0;
}
2.默认参对函数重载有影响
void Add(int n)
{
}
void Add(int n, float f = 3.2f)
{
}
int main()
{
Add(36.5);
return 0;
}
内联函数
函数调用
1.参数入栈
2.返回地址入栈
3.保存栈帧
4.分配局部变量空间
5.保存寄存器环境
6.执行函数体
7.还原寄存器
8.释放局部变量空间
9.还原栈帧
10.返回调用点
int Max(int n1, int n2)
{
return n1 > n2 ? n1 : n2;
}
#define MAX(x,y)(x>y>x:y)
/*
短函数:体积小 效率低,方便调试 -->时间换空间
宏:体积大 效率高,不方便调试 -->空间换时间
*/
/*
内联函数:既可以像函数一样可以调试,也可以在调用点像宏一样展开.利用inline定义
debug:任何函数都不会展开,release需要开Ob1选项
*/
inline int Max(int n1, int n2)
{
return n1 > n2 ? n1 : n2;
}
int main(int argc,char * argv[])
{
std::cout << Max(argc, argv[0][2]);
}
VS改内联规则:
inline:建议编译器内联,但是能不能够内联成功,看编译器。
inline int Foo(int n1)
{
if (n1 == 0)
{
return 0;
}
return Foo(n1 - 1) + n1;
}
int main(int argc, char* argv[])
{
std::cout << Foo(argc);
}
如下图,。函数调用了
内联函数不能拆分到头文件和Cpp中。一般声明和实现都放在头文件里否则会报错