命名空间namespace
可以在里面定义变量,函数,结构体等,命名空间可以嵌套,同一个工程的命名空间可以重名(编译器会自动合并)
是为了解决c语言里面的重定义的问题,就是命名冲突问题,自己定义的新变量名和库函数名冲突了。C++引入了命名空间来解决这个问题。
[c++编译器下]C语言中不同的作用域(全局,局部)可以定义同名变量,怎么强制范围全局变量?使用::
域作用限定符,::a
表示访问全局变量的a
//这种情况下会报错,因为rand是stdlib的库函数名,重定义了
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{
printf("%d\n", rand);
return 0;
}
//修改如下
#include <stdio.h>
#include <stdlib.h>
namespace yyq
{
int rand = 10;//这个是全局变量,只不过是在yyq的命名空间里
}
int main()
{
printf("%d\n", rand);//此时访问的是stdlib的库函数rand,因为此时rand函数在全局变量里,而rand在yyq的命名空间里
printf("%d\n", yyq::rand);//这里访问的是yyq命名空间里的rand
return 0;
}
命名空间只影响编译查找规则,只是限定域。不影响变量的生命周期。
编译器的默认查找规则是先找局部的,再找全局的,不会主动去命名空间里面去找。
std是c++官方库内容定义的命名空间。
使用方式
加命名空间名称及作用域限定符;std::cout
使用using将命名空间中某个成员引入;using N::b;
使用using namespace 命名空间名称 引入。using namespace std;
建议部分展开,把常用的展开就行,自己定义的时候避免跟常用的重名即可
IO流
cout cin (c是consloe的缩写)对比c语言的 scanf printf。使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
cout
流插入运算符,可以自动识别类型;
cin
流提前运算符,可以自动识别类型。
<<是流插入运算符,>>是流提取运算符。
但是涉及到格式控制(比如保留几位小数,对齐方式等)就用printf,cout的比较麻烦,c++可以兼容c的语法,所以printf、cout和scanf、cin可以结合使用。
缺省参数
c语言不支持,仅c++可用。函数定义中给形参一个默认值,从而调用该函数传实参的时候可以不传参数,使用默认值。
int func(int a = 0)
{
return a * a;
}
int main()
{
int ret = func(10);
return 0;
}
全缺省参数
全部形参都有默认值。
半缺省参数
当有多个形参时,只能从右往左连续缺省,即调用函数时要从左向右连续给实参值,不能间隔;
缺省参数不能在函数声明和定义中同时出现。【如果声明(.h)与定义(.cpp)处形参同时有默认值,恰巧这两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值。一般写在.h文件里/声明处】
适用场景
可以修改默认空间大小,在已知本次要开辟的空间大小的情况下,就可以用缺省值来修改,可以避免后期扩容,不用malloc
。
struct Stack {
int* a;
int top;
int capacity;
};
void StackInit(struct Stack* ps, int defaultCapacity = 4)
{
ps->a = (int*)malloc(sizeof(int) * defaultCapacity);
ps->capacity = defaultCapacity;
ps->top = 0;
}
函数重载
是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这
些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
类型顺序不同 的重点是类型,比如只有两个int互换位置就不构成重载,返回值不同但函数名和参数相同也不构成重载。
// 1、参数类型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
// 2、参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
自动识别类型是因为有函数重载的。
//这种情况下有二义性,如f(),无参调用时有歧义。重载和缺省参数混在一起,容易有二义性
void f()
{
cout << "f()" << endl;
}
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
如何支持?
c语言不支持重载,是因为 在预处理(-E .i,展开头文件、去注释)、编译(-S .s,语法分析、词法分析、语义分析、符号汇总)、汇编(-c .o,形成符号表、二进制指令)、 链接(合并段表、符号表合并及重定位)。
符号表里面放的是函数名及其地址。C的符号表,用的就是函数名原名;C++的符号表,g++编译器下,函数修饰后变成【_Z+函数名称长度+函数名+类型首字母】。因此c++支持重载。
注意:每个链接器都有自己的函数名修饰规则。
仅返回值不同无法构成重载的原因并不是函数名修饰规则,而是 调用时的二义性,调用时无法知道返回值类型。