文章目录
前言
新人发文,欢迎大家指出我的不足
命名空间
为什么要有命名空间
因为在编译的过程中会有可能会出现很多同名函数,变量,和类。为了防止他们之间的冲突,而诞生了命名空间。
关于命名空间的展开
大家在看代码的时候也许会经常看到这一句
using namespace std;
这句话的意思其实是,展开标准库的命名空间,其中std就是标准库。
一般这段代码使用与日常写代码,练习,写项目的时候并不会用。
理由如下:
#include<iostream>
using namespace std;
namespace MY_kun // 这段代码的意思是建立一个 名字为 MY_kun 命名空间,
{
int a = 10;
}
int a = 20;
int main()
{
cout << a << endl;
return 0;
}
这段代码是可以编译成功的
不过如果展开了命名空间的话就会报错
使用这句代码展开此命名空间
using namespace MY_kun;
获得报错
在不展开命名空间的情况下,我们可以通过这样的方法去使用命名空间
#include<iostream>
namespace MY_kun // 这段代码的意思是建立一个 名字为 MY_kun 命名空间,
{
int a = 10;
}
int a = 20;
int main()
{
std::cout << a << std::endl;
std::cout << MY_kun::a << std::endl;
return 0;
}
输出结果如下
此处使用的方法便是 在需要使用的函数或者变量值的前面加上命名空间的名字和两个英文冒号
不过这样的方法还是有些繁琐的,所以我们可以通过这样的方法一次搞定经常要使用的函数
#include<iostream>
namespace MY_kun // 这段代码的意思是建立一个 名字为 MY_kun 命名空间,
{
int a = 10;
}
using std::cout;
using std::endl;
int a = 20;
int main()
{
cout << a << endl;
cout << MY_kun::a << endl;
return 0;
}
此处的两句话可以一次性帮我们解决大量繁琐的输入工作
命名空间的嵌套
在命名空间中是支持嵌套的,比如说这样
#include<iostream>
namespace MY_kun // 这段代码的意思是建立一个 名字为 MY_kun 命名空间,
{
int a = 10;
namespace QE
{
int a = 30;
}
}
using std::cout;
using std::endl;
int a = 20;
int main()
{
cout << a << endl;
cout << MY_kun::a << endl;
return 0;
}
而使用方法也是很简单的,和普通的命名空间一样
cout << MY_kun::QE::a << endl;
最后的输出结果是
同名的命名空间
为了大家更好理解此处,我创建了两个头文件,分别叫做test1.h和test2.h,其中命名空间的名字都为T
#pragma once
//test1.h
namespace T
{
int a = 40;
}
#pragma once
//test2.h
namespace T
{
int b = 50;
}
在源文件中包含以下这两个头文件,使用其中变量的方法十分的简单
cout << T::a << endl;
cout << T::b << endl;
大家可以看到由于这两个命名空间的名字相同,在链接的时候是会合并的,不过这也带来了一个问题,那就是两个名字相同的命名空间中不能有相同的变量名字
比如
#pragma once
//test2.h
namespace T
{
int a = 0;
int b = 50;
}
此时去运行代码,编译器提示
在日常使用的过程中,大家要注意
缺省参数
缺省参数的概念
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该
形参的缺省值,否则使用指定的实参。
下面我举个例子
void print(int a = 0)
{
cout << a << endl;
}
int main()
{
print();
print(10);
return 0;
}
在这段代码中,函数print是需要传入值的,但是由于在定义中说明了a的默认值是0,所以即使没有传入参数也是不会报错的
以下是输出结果
缺省参数的分类
1.全缺省参数
顾名思义,全缺省参数是指函数的参数可以全部缺省的,就像上文中写的代码
再来几个例子
void func(int a = 10, int b = 20, int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main()
{
func();
func(0,0,0);
return 0;
}
输出值
2.半缺省参数
与全缺省参数相对应的
void func1(int a , int b = 20, int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main()
{
func1(0);
func1(0,0,0);
return 0;
}
结果为
3.注意事项
- 半缺省参数必须从右往左依次来给出,不能间隔着给
用之前写好的函数来举例子
void func1(int a , int b , int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
以上代码在编译的过程中是不会出问题的
void func1(int a = 10, int b , int c )
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
上面这段代码就会产生报错为
- 缺省参数不能在函数声明和定义中同时出现
还是拿上面的函数来举例子
void func1(int a, int b = 20, int c = 30);
void func1(int a , int b = 20, int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main()
{
return 0;
}
当在定义和声明中同时出现之后,产生如下报错
所以个人建议将缺省参数写在声明中
函数重载
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数
的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
1.参数类型不同
int Add(int a, int b)
{
return a + b;
}
double Add(double a, double b)
{
return a + b;
}
这两个函数的函数名是一样的,但是由于有不同的参数类型,所以构成函数重载
2.参数个数不同
int abc(int a,int b)
{
return a + b;
}
int abc(int a)
{
return a;
}
3.参数类型的顺序不同
void fun(int a, char b)
{
cout << "fun(int a, char b)" << endl;
}
void fun(char a, int b)
{
cout << "fun(char a, int b)" << endl;
}
注意
只有以上的代码类型可以构成函数重载,形如以下的类型是无法构成函数重载的
double division(int a, int b)
{
return 1.0 * (a / b);
}
int division(int a, int b)
{
return 1.0 * (a / b);
}
//注意,这是错误写法
void division(int a = 10)
{
cout << a << endl;
}
void division(int a)
{
cout << a << endl;
}
//错误写法
形似以上缺省参数的函数并不能形成函数重载
引用
引用的概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它
引用的变量共用同一块内存空间。
类型& 引用变量名(对象名) = 引用实体;
引用的特性
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,再不能引用其他实体
以下是一段使用的引用语法的代码:
int main()
{
int a = 10;
int& c = a;
cout << a << endl;
cout << c << endl;
cout << &a << endl;
cout << &c << endl;
c = 20;
cout << a << endl;
cout << c << endl;
return 0;
}
}
所得的结果是
在上面的代码中,c是a的引用
从这段代码的运行结果不难看出来,a与c共用一个地址,修改c的值也会影响到a的值
同时,一个实体可以有多个引用,引用也可以被引用,如下
常引用
int main()
{
const int a = 10;
//int& b = a; // 编译失败
const int& c = a;
return 0;
}
运行以上代码,发现以下代码编译失败
int& b = a;
此时我们认为,const所修饰的变量,其限定条件是多的,也就是所谓的 “低权限”
在C++中,权限的减少和权限的平移是可以被接受的,但是权限的扩大是不可以被接受的
int ac = 20;
const int& bc = ac;
在这两句代码中,是权限的减少
在这之后,我们无法通过bc来修改实体的值,但是我们还是可以通过ac来修改实体的值
接下来来看这段代码,其中第一句代码报错,是因为它直接等于了一个常量的值,而常量是不能被修改的,所以要用const去修饰这段代码
可以简单的理解为 第一句代码想要执行权限的放大,所以没有成功
而第二句代码则进行了权限的平移,所以成功了
在这段代码中,第二句编译器报错了,但是第三句编译通过了
其原因是,在赋予变量的过程中,会出现一个临时变量,临时变量属于常量
所以可以简单理解为当跨类型引用的时候相当于权限的提升,自然就无法成功
注:这与截断无关
不过之前我们曾说过,引用与赋值不一样,那为什么还会出现临时变量呢
此时我们打开调试转到反汇编
我们此时发现,引用的底层逻辑与指针的逻辑类似,之前的问题也就迎刃而解
引用的应用场景
1.做参数
以下是一个我们在C语言中写的交换函数
void swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
以下是一个我们在C++中写的交换函数
void swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
相交于C语言可以简化一些
2. 做返回值
如下
int& countA(int m)
{
static int n = m;
n++;
return n;
}
int& count(int x)
{
int n = x;
n++;
return n;
}
而返回值不但可以使用int&来接收,也可以使用int来接收
不过其中需要注意的点有
函数 countA 的变量前有修饰 static 将其存放于静态区中
但是函数count的变量存在于栈帧中,所以可能会被覆盖,如下:
会出现随机值的现象
总结:
1、基本任何场景都可以用引用传参。
2、谨慎用引用做返回值。出了函数作用域,对象不在了,就不能用引用返回,还在就可以用引用返回。
总结
这篇文章包括了新手入门C++可能会遇到的问题,还请大家多多关照