前言
博目前正在学习c++,在接下来的学习过程中会给大家分享我的学习心得。但因为博主认知不全,如出现什么错误,希望大佬们可以多多指点。
基础语法
命名空间
因为在c/c++中,我们需要定义大量的变量,这时就会遇上一个问题,那就是命名冲突,我们拿c语言来举个栗子
#include<stdio.h>
int main()
{
int printf = 0;
printf("%d\n");
return 0;
}
大家可以拿到自己的编译器上去跑跑,会发现这个程序是跑不过去的,那我们来看看报错信息
图中显示报错:项不会计算为接受 1 个参数的函数。 那这是怎么一回事呢?
我们知道在预处理阶段,头文件会在展开,虽然printf被定义为打印函数,但是在局部上printf被我们定义为整形,编译器在读到printf("%d\n");这条语句时会现在当前作用域(main函数内)寻找printf的定义,此时printf是整形(就近原则),所以不能进行函数的相关操作。 补充:这就是为什么当局部变量和全局变量重名,局部变量优先的原因。
但是有的朋友想问了,我就是想定义一个printf的整形变量,又不影响printf函数的使用,那有什么办法吗?
这个时候c++就能实现这种情况了,那就是定义命名空间,首先我们要介绍一个关键词:namespace
语法:
namespace 空间名字
{
....//命名空间中的内容既可以是变量,也能是函数
}
而c++里printf函数的命名空间是std。
#include<iostream>
int main()
{
int printf = 0;
std::printf("%d\n",printf);
return 0;
}
::是作用域限定符,指定了第二个printf是std内的。而namespace的作用就是可以让我们创建一个新的作用域。
#include<stdio.h>
namespace N1 //定义了一个域,解决了命名空间的问题,里面可以定义变量和函数等
//同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
{
int scanf;
int Add(int left, int right)
{
return left + right;
}
namespace N3//可以嵌套 N1::N3::Sub(1,2);
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
int main()
{
std::scanf("%d", &N1::scanf);
printf("%d\n", N1::scanf);
//未指定的在全局和局部中找
printf("%x\n", scanf);
//指定了N1作用域
printf("%x\n", &(N1::scanf));
printf("%d\n", N1::Add(2, 3));
return 0;
}
我们可以看出两个scanf的地址不同,这也证明了它们确实在不同命名空间,而编译器也能区分出它们。
命名空间的使用方式
1.指定命名空间 语法:作用域名+作用域限定符
namespace N4
{
int n;
int c;
}
int main()
{
N4::n = 1;
return 0;
}
优点:最规范的,不会造成命名作用域的污染
缺点:每次都要指定,有点麻烦
2.使用using namespace将命名空间引入
namespace N4
{
int n;
int c;
}
using namespace N4;
int main()
{
n = 1;
return 0;
}
优点:十分方便,适合平常练习使用
缺点:相当于直接将N4展开了,没有起到隔离作用了。
3.使用using将命名空间中成员引入
namespace N4
{
int n;
int c;
}
using N4::c;
int main()
{
c = 1;
return 0;
}
int n = 0;
优点:将常用的展开,取两家之长
缺点:比较方法2麻烦
c++的输入和输出
输出函数:cout 头文件:iostream.h
既然是学习一个新的语言,那么我们怎么能不写出那个顶级程序呢
#include<iostream>
using std::cin;
using std::endl;
using std::cout;
int main()
{
cout << "hello world" << endl;//endl等同于\n
return 0;
}
输入函数:cin 头文件: istream
#include<iostream>
#include<istream>
using std::cin;
using std::endl;
using std::cout;
int main()
{
int a = 0;
cin >> a;
cout << a << endl;
return 0;
}
我们可以看到不管是cin还是cout都没有像printf和scanf一样指定数据类型,使用起来十分方便。
C++的输入和输出 和C相比更加安全和智能方便。
缺省参数
c++函数支持缺省参数,那什么是缺省参数呢?
#include<iostream>
int Add(int a = 1, int b = 2)//就是这样
{
return a + b;
}
int main()
{
int ret = Add();
std::cout << ret << std::endl;
return 0;
}
当我们没有向Add函数中传参时,Add函数使用了缺省参数1和2。缺省就是默认的意思,当我们没传参数时,编译器就使用缺省参数,当我们传了参数时就会使用我们的参数。还可以只传一部分参数,另一部分使用缺省参数哦。
缺省参数也分全缺省和半缺省
半缺省需要注意几点:
1、必须从右边的参数开始缺省
2、必须连续
#include<iostream>
int Add(int a , int b = 2)
{
return a + b;
}
int main()
{
int ret = Add(1);
std::cout << ret << std::endl;
return 0;
}
合法
#include<iostream>
int Add(int a , int b = 2)
{
return a + b;
}
int main()
{
int ret = Add(1);
std::cout << ret << std::endl;
return 0;
}
#include<iostream>
int Add(int a=1 , int b)
{
return a + b;
}
int main()
{
int ret = Add(1);
std::cout << ret << std::endl;
return 0;
}
函数重载
1、c++支持函数出现重名,但是它们的参数必须不同(个数或者类型)ps:返回值不同不构成函数重载
2、当出现两个功能相似,但参数不同时,函数重载就派上了用场。
#include<iostream>
int Add(int a, int b)
{
return a + b;
}
double Add(double a, double b)
{
return a + b;
}
int main()
{
std::cout << Add(1, 2) << std::endl;
std::cout << Add(1.11, 2.05) << std::endl;
return 0;
}
那为什么C++支持函数重载呢?
1、名字修饰规则
2、一个程序跑起来会经历预处理,编译,汇编,链接最后形成可执行文件
3、当一个工程中函数声明和定义分别在两个文件时,链接过程会把汇编形成的符号表链接在一起
4、这个时候会通过识别名字的方式找到链接对象
5、C的函数命名方式就是函数名,而C++的命名方式(Linux)为_Z+函数长度+函数名+类型首字母
6、所以在链接时因为C++的命名特点,函数名相同的函数如果参数的个数或类型不同时构成函数重载(C也因此不支持函数重载)