目录
前言:
1 命名空间
2 输入和输出
3 缺省参数
5 函数重载
前言:
C++与C语言是有一定交集的,可以理解为本贾尼在使用C语言的时候认为有缺陷,于是加了一些小语法进行改良,后来经过委员会的修改,C++98问世了,是第一部标准版本。
学习C++之前我们先来看一个代码:
int rand = 0;
int main()
{
printf("%d ",rand);
return 0;
}
这个代码在C语言里面是有个大问题的,就是重定义的问题,写过猜随机数的朋友都知道rand是一个函数,我们常说命名不能以关键字命名,实际上我们定义变量的时候定义成函数的名字也会冲突,这时候本贾尼不舒服了,觉得这个名字我一定要取,所以加入了命名空间(namespace)的概念。
C++创建文件的时候后缀是.cpp,与C语言有区别。
1 命名空间
命名空间(namespace),我们可以理解为创建了一个新的域,比如创建变量的时候有局部域,全局域,命名空间就是单独创建一个域出来:
namespace XY
{
int rand = 1;
}
花括号里面的空间就是名为XY的一块命名空间,与结构体不同的是花括号最后没有分号,那么我们是不是可以打印这个值了?实际上并不能,就像一块地被占用了,没有地主人的声明我们是不能进入的:
正确的使用方法是加一个using ,即展开命名空间,使用的变量前面加上两个冒号,冒号左边是要使用的空间名,如果是空,默认在全局域寻找该变量,使用变量的时候系统也是有查找顺序的:
先在局部域查找,再到全局域查找,最后到命名空间里面查找,这其实也是为什么局部变量和全局变量命名冲突了优先局部变量。
以下是两段参考代码:
namespace XY
{
int rand = 1;
}
using namespace XY;
int main()
{
printf("%d ", XY::rand);
return 0;
}
int a = 10;
int main()
{
int a = 1;
printf("%d ", ::a);
return 0;
}
命名空间解决的是命名冲突的问题,当命名空间里面的成员足够多的时候,比如有数组,有函数,有指针等到,我们只想用里面的一个怎么办呢?很简单,直接指定就行了。
namespace byte
{
int a = 1;
int b = 2;
int c = 3;
int Add(int a, int b)
{
return a + b;
}
}
using byte::Add;
using byte::a;
int main()
{
printf("%d ", Add(1, 2));
printf("%d ", a);
return 0;
}
如果我们要展开整个命名空间,就需要在using后面加namespace,如果我们只是使用某个命名空间里面特定的成员,我们指定using就行了,这里是命名空间的一种用法——引入成员。
但是命名空间名字一样怎么办?
名字一样的时候就相当于是两块空间合并:
namespace byte
{
int a = 1;
}
namespace byte
{
int a = 10;
int c = 0;
}
int main()
{
printf("%d ",byte::a);
return 0;
}
这时候就会报错,重定义。
命名空间也可以进行嵌套使用:
namespace byte
{
int a = 1;
namespace bit
{
int a = 10;
}
}
int main()
{
printf("%d ",byte::bit::a);
return 0;
}
2 输入和输出
学习C语言的时候我们第一堂课学的是打印Hello world ,那么C++怎么实现呢?
C++的输入输出用到的是cout和cin,其中的c对应的是控制台console,out和in不用多说,那我们打印一个试试:
int main()
{
cout << 1;
int a = 0;
cin >> a;
cout << a;
return 0;
}
cout后面加两个小于号就是输出,可就这段代码是打印不出来的,因为它们对应的头文件是iostream,与C语言不同的是他不用加.h后缀,光加头文件还不行,cout和cin在这个头文件里面不错,但是C++为了防止命名冲突,加了命名空间,空间的名字是std,所以正确用法是:
using namespace std;
using std::cout;
using std::endl;
using std::cin;
int main()
{
cout << 1 << endl;
int a = 0;
cin >> a;
cout << a;
return 0;
}
平时写代码的时候我们直接展开整个命名空间是没有问题的,做项目的时候为了防止定义的类型与库里面的冲突,常常指定展开。
endl可以理解为是换行。
int main()
{
cout << "Hello world!" << ' ' << 1234 << endl;
return 0;
}
cout cin这种输入输出的方式是很方便的,不像printf还要指定占位符,cout cin是可以自动识别数据类型的,这是一个优势,但是打印的时候如果涉及到了精度,我们不妨用printf,cout也可以指定精度但是比较麻烦,c++兼容C语言那我们就看哪个方便咯。
3 缺省参数
缺省参数听起来可能难以理解,换个名字,叫做默认参数,就容易理解了,缺省参数就是指创建函数的时候给参数一个默认值:
using namespace std;
int Add(int x = 1, int y = 10)
{
return x + y;
}
int main()
{
cout << Add();
return 0;
}
Add函数有两个参数,我们一个不给,那么使用函数的时候就会使用给的默认参数。
上面的两个参数全部都有默认值,那么这种被称为全缺省参数,另一种就是半缺省参数,这里的半不是指一半,是指只要有参数没给默认值的情况下就被称为半缺省参数。
int Sub(int x,int y = 1)
{
return x - y;
}
int main()
{
cout << Sub(1);
return 0;
}
但是半缺省参数有个规定:参数只能从右往左缺省。
int Add(int x = 1,int y,int z)
{
return x + y + z;
}
这样就是错误,存在歧义,给参数的时候是从左往右给还是从右往左给呢,所以委员会规定只能从右往左缺省:
int Add(int x,int y = 1,int z = 2)
{
return x + y + z;
}
int main()
{
cout << Add(1);
return 0;
}
缺省参数还有两个要注意的点就是:
1 缺省参数在定义和声明的时候应该保持一致。
2 半缺省参数不能跳着给。
3 缺省值只能是常量或者全局变量。
4 C语言不支持缺省类型。
5 函数重载
void Func(int ,int )
{
cout << 111;
}
void Func()
{
cout << 222;
}
int main()
{
Func();
return 0;
}
上述代码会报错吗?函数名是一样的。
在C语言里面这段代码是会报错的,但是C++里面就不会,因为C++支持函数重载,C语言不支持函数重载。
函数重载成立的条件是有函数名相同,在同一个域中,参数个数不同,参数类型不同,参数顺序不同。
前两个条件必满足,后面三个条件满足任意一个就满足函数重载,函数重载是为了解决函数名相同的问题而诞生的,函数重载有个很智能的点就是系统会根据你给参数的情况来判断该调用哪个函数。
void Func(int x = 1,int y = 1)
{
cout << 111;
}
void Func()
{
cout << 222;
}
int main()
{
Func();
return 0;
}
但是我们应该避免这种带有歧义的代码,虽然参数类型确实不同,但是不传参的话任意的Func函数都可以被调用,所以就会报错。
那为什么C++支持函数重载而C语言不支持呢?
详细介绍起来可能有点麻烦,这里牵扯到函数命名规则以及编译等知识,所以我们简单介绍即可:
C语言在链接的时候是通过函数名去找函数栈帧的,那么函数名一样的情况下就会导致报错,C++不一样,C++会变相的给函数改一个名字,在链接的时候会通过修改后的名字去查找。
int Func();
int main()
{
Func();
return 0;
}
括号里面的一长串就是函数名被修饰过后的名字,?Func@@YAHXZ,所以C++调用函数的时候是通过这个名字去寻找的,C语言就是直接通过名字找,这就是为什么C++支持函数重载C语言不支持函数重载。
感谢阅读!