namespace N1
{
int a;
int b;
int Add(int left, int right)
{
return left + right;
}
namespace N2
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
namespace N1
{
int a;
int b;
int Add(int left, int right)
{
return left + right;
}
namespace N2
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
namespace N1
{
int Mul(int left, int right)
{
return left * right;
}
}
#include<iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
int a;
double b;
cin >> a >> b;
cout << a << b << endl;
return 0;
}
缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个缺省值
在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参
cpp复制代码
#include<iostream>
using std::cout;
using std::endl;
void Fun(int a = 10)
{
cout << a << endl;
}
int main(void)
{
Fun();//没有指定实参则采用缺省值
Fun(314);
return 0;
}
缺省参数的类型
|----------------|
| 🌤️全缺省:形参都是表达式 |
cpp复制代码
#include<iostream>
using std::cout;
using std::endl;
void Fun(int a = 10,int b = 20,int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main(void)
{
Fun(1);
return 0;
}
注意:
<1>缺省参数不是要全部传完,没有指定实参采用该形参的缺省值
<2>缺省值必须从左往右依次传,不可以间隔
|------------------|
| 🌤️半缺省:形参部分没有表达式 |
cpp复制代码
#include<iostream>
using std::cout;
using std::endl;
void Fun(int a,int b = 20,int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main(void)
{
Fun(1);
return 0;
}
注意:
<1>半缺省参数必须从右往左依次来给出,不能间隔着给
cpp复制代码
void Fun(int a = 10,int b = 20,int c)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main(void)
{
Fun(1);
return 0;
}
因为第三个形参 c 不是表达式,没有缺省值,而我们实参传的数值是传给 a 的所以报错
<2>缺省参数不能在函数声明和定义中同时出现
cpp复制代码
#include<iostream>
using std::cout;
using std::endl;
void Fun(int a = 10, int b = 20, int c = 30);
int main()
{
Fun(1);
return 0;
}
void Fun(int a = 10, int b = 20, int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
const int a = 10;
//int& ra = a; //该语句编译时会出错,a为常量
const int& ra = a;
double b = 3.14;
//int& rb = b; //该语句编译时会出错,类型不同
double& rb = b;
int c = 10;
const int& rc = c;
加了const 该变量是不能修改的 ,即成了一种常量,可以理解为只读型
而没加 const 的可理解为可读可写型
|---------------------------------------------------------------------------------|
| const int a = 10; int& ra = a;对常量a进行引用,那么我就可以通过引用ra去修改a的值,权限放大了所以是不行的 |
|------------------------------------------------------------------------------|
| int c = 10;const int& rc = c;对变量c进行引用,并将c置为不可修改的常量,权限的缩小所以是可行 |
|---------------------------------------------------------------------------|
| const int a = 10; const int& ra = a;都是const加以修饰的同类型变量,权限的平移是可行的 |
总结
<1>权限只能缩小,不能放大,放大就会报错
<2>权限放大和缩小只针对引用和指针
<3>使用引用传参,函数内不改变参数,尽量使用 const 引用传参
引用的使用场景
做参数
💞<1>还记得我们之前写过的两数交换的代码吗?我们之前传的是指针 ,我们可以用引用代替
cpp复制代码
#include<iostream>
using std::cout;
using std::endl;
void Swap(int& n, int& m)
{
int tmp = n;
n = m;
m = tmp;
}
int main()
{
int a = 10, b = 20;
Swap(a, b);
cout << a << endl << b << endl;
return 0;
}
#include<iostream>
using namespace std;
int& Count()
{
int n = 10;
return n;
}
int main()
{
int& ret = Count();
cout << "ret = " << ret << endl;
cout << "ret = " << ret << endl;
return 0;
}
让我们来分析分析,以上打印的值都是 10 吗?
我们发现我们打印的第二个ret竟然是随机值,这是为什么呢?
因为局部变量存储在系统的栈区,出了定义域就会销毁
🌤️第一次打印原值是因为编译器在释放时会进行一次保留
Count 函数并不是直接返回 n 的
因为 Count 函数在调用结束后会销毁它所在的栈帧 ,连同n 会一起销毁,所以编译器会先保存 n 的值到一个寄存器 中,再销毁栈帧 ,然后返回寄存器的值给 ret
🌤️第二次出现乱码是因为赋值后寄存器的空间被编译器销毁
当我们用上面的代码,返回的是 n 的引用时,这就不安全了。因为返回的是 n 的引用,不会创建临时空间给n ,而是直接返回n 。 但是返回之后n 所在的函数栈帧会被销毁,所以连同n 一起销毁了,但是此时 ret 是n 这块已经不属于自己的空间的拷贝,所以ret 是违法
那我们想二次调用 n 该怎么办呢?只要不销毁n 就可以了,我们可以给 n 开辟静态空间:
(正确写法)
cpp复制代码
#include<iostream>
using namespace std;
int& Count()
{
static int n = 10;
return n;
}
int main()
{
int& ret = Count();
cout << "ret = " << ret << endl;
cout << "ret = " << ret << endl;
return 0;
}
此时 n 是被 static 修饰过的变量,可以用引用进行返回了,因为 n 是在静态区开辟的空间在内存的堆区,而函数是在栈区开辟的空间,所以不会被销毁。其次因为在堆区返回的时候就不需要借助寄存器的临时拷贝了。
⭐局部变量用 static 修饰,出作用域后不销毁,可以传引用返回
⭐没有用 static 修饰的局部变量,出了作用域会被销毁栈,必须用传值返回
⭐引用作为函数的返回值时,必须在定义函数时在函数名前&
⭐用引用作函数的返回值的最大的好处是在内存中不产生返回值的副本(寄存器)
我们在举一个栗子~
cpp复制代码
#include<iostream>
using namespace std;
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;
return 0;
}
#include<iostream>
using namespace std;
int main()
{
int a = 10;
//指针存储a的地址
int* pa = &a;
//b是a的引用
int& b = a;
return 0;
}
✨没有NULL引用,但有NULL指针
cpp复制代码
#include<iostream>
using namespace std;
int main()
{
int* a = NULL;
int& b = a;
return 0;
}
✨在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数
cpp复制代码
#include<iostream>
using namespace std;
int main()
{
double a = 10;
double* b = &a; //指针取地址
cout << sizeof(b) << endl;
double& c = a; //引用
cout << sizeof(c) << endl;
return 0;
}
✨引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
cpp复制代码
#include<iostream>
using namespace std;
int main()
{
double a = 10;
double* b = &a;
cout << b << endl;
b++;
cout << b << endl;
double& c = a;
cout << c << endl;
c++;
cout << c << endl;
return 0;
}