学习C++ Day 01
知识1
命名空间:避免命名冲突与污染,定义命名空间需要用到 namespace 关键字,后面跟空间名字,紧接{},{}中即为命名空间成员。
namespace yx
{
int rand = 10;
}
int main()
{
printf("%d\n", yx::rand);
}
访问变量时按此顺序访问“局部域 -> 全局域 -> 展开的命名空间域(using namespace yx) or 指定访问的命名空间域(::)”。
命名空间有三种使用方式:
(1)加命名空间名称及作用域限定符
int main()
{
printf("%d\n", N::a);
return 0;
}
(2)使用using将命名空间中某个成员引入
using N::b;
int main()
{
printf("%d\n", N::a);
printf("%d\n", b);
return 0;
}
(3)使用using namespace 命名空间名称引入
using namespace N;
知识2
C++输入&输出:cout&cin,使用时必须包含 <iostream> 头文件以及按命名空间使用方法使用 std(C++标准库的命名空间名)。cout 和 cin 是全局的流对象,endl 是特殊的C++符号,表示换行输出。<<是流插入运算符,>>是流提取运算符。与 printf 和 scanf 的区别是更方便,可自动识别变量类型。
#include <iostream>
using namespace std;
int main()
{
int a;
double b;
char c;
//可自动识别类型
cin>>a;
cin>>b>>c;
cout<<a<<endl;
cout<<b<<" "<<c<<endl;
return 0;
}
通常不会全部展开 std,会用 std::cout 或 using std::cout 只展开常用的。
知识点3
缺省参数:可以认为是函数传参的默认值,当调用函数需要传参但未给时便用此值。有半缺省和全缺省两种,全缺省是全部参数都给缺省值,半缺省就是只给一部分,参数是从左往右给的,所以半缺省只能缺左边的不然无法匹配。半缺省不能间隔着给。缺省参数不能在函数声明和定义中同时出现,一般给声明。给定义会在编译阶段报错,因为在链接阶段才会将定义的函数链接在一起,若只传部分参数,会被认为参数传的不完整。
void Func(int a = 10, int b = 20, int c = 30)
{
......
return 0;
}//全缺省
void Func(int a, int b = 10, int c = 20)
{
......
return 0;
}//半缺省
知识点4
函数重载:就是可以有重名函数,有个前提是形参列表(参数个数、参数类型或类型循序)不同,其实底层就是将参数加入函数名后面依此区分,返回值不同不构成重载。比如一个函数声明为 void Func(int a, int b),另一个为 void Func(double a, double b),则这俩函数构成重载,在底层代码里其实分别为 Funcii 和Funcdd。
知识点5
引用:给已存在变量取别名,编译器不会为其开辟内存空间,它和它引用的变量共用同一块内存空间。
void TestRef()
{
int a = 10;
int& ra = a;
printf("%d\n", &a);
printf("%d\n", &ra);
return 0;
}
引用特性:
(1)引用在定义时必须初始化
(2)一个变量可以有多个引用
(3)引用指向不可变(引用一旦引用一个实体,再不能引用其他实体)
使用场景:
(1)引用做参数:做参数有两个大作用,其一作为输出型参数(就是在函数内部改变,需要在外面拿到,类似想要改变变量就需要传指针,想要改变指针就需要传二级指针,通过引用就可以直接传引用这样就可直接实现),其二可以提高效率(以值作为参数或返回值,函数不会直接传递实参或将变量本身直接返回,而是返回其的一份临时拷贝,因此效率低下,引用则不会生成临时拷贝效率高)
(2)引用做返回值:做返回值同样有两个好处,一个同上可提高效率,另一个为引用做返回值可直接修改和获取返回值。一般情况下都是静态引用返回,如下有五个场景分析。
场景一:此场景没有问题,因为 n 此时在静态区,函数结束后不会被销毁因此没问题。
//传值返回
int Count()
{
static int n = 0;
n++;
//......
return n;
}
int main()
{
int ret = Count();
return 0;
}
场景二:此场景函数结束时 n 会被销毁,此时 ret 是不确定的。
int Count()
{
int n = 0;
n++;
//......
return n;
}
int main()
{
int ret = Count();
return 0;
}
场景三:此时无需生成临时变量且不会被销毁,效率高,无问题。
//传引用返回
int& Count()
{
static int n = 0;
n++;
//......
return n;
}
int main()
{
int ret = Count();
cout << ret <<endl;
return 0;
}
场景四:这里打印 ret 的值是随机的,如果函数结束,栈帧销毁,没清理栈帧,那么 ret 的值侥幸正确;如果函数结束,栈帧销毁,清理栈帧,那么 ret 的值是随机值。
int& Count()
{
int n = 0;
n++;
//......
return n;
}
int main()
{
int ret = Count();
cout << ret << endl;
return 0;
}
场景五:此时第一个 ret 的值可能是1也可能是随机值,第二个 ret 一定是随机值。
int Count()
{
int n = 0;
n++;
//......
return n;
}
int main()
{
int& ret = Count();
cout << ret << endl;
printf("SSSSSSSSSSSSSSSSSSS\n");
cout << ret << endl;
return 0;
}
总结:基本所有场景都可用引用传参;谨慎用引用做返回值。出了函数作用域,对象不在了,就不能用引用返回了,还在就可用。
常引用:
int main()
{
const int a = 0;
//int& ra = a; //该语句编译时出错,引用过程中权限不能放大
const int c = 0;
int& d = c; //该语句没问题,c 拷贝给 d ,没有放大权限,因为 d 的改变不影响 c
int x = 0;
int& y = x; //引用过程中,权限可平移
const int& z = x;0 //引用过程中,权限可缩小
++x; //可以,x 权限未被限制,但 z 不可变,但 x 变 z 也变
//++z; //不可
double dd = 1.11;
int ii = dd; //隐式类型转换
//int& rii = dd; //不同类型转化会产生临时变量,临时变量又具有常性,因此发生了权限放大
const int& rii = dd; //此时可以,权限平移
return 0;
}
int func1()
{
static int x = 0;
return x;
}
int& func2()
{
static int x = 0;
return x;
}
int main()
{
//int& ret1 = fun1(); //不可,传值有临时拷贝,发生了权限放大
const int& ret1 = func1(); //可,权限平移
int ret1 = func1(); //拷贝
int& ret2 = func2(); //可,权限平移
const int& ret2 = func2(); //可,权限缩小
}
int main()
{
int i = 1;
double j = 1.11;
if(j > i) //此时 i 提升,会生成 double 临时变量
{
cout << "xxxxx" << endl;
}
return 0;
}
引用和指针的区别:
引用语法层面:不开空间,是对其取别名
指针语法层面:开空间,存储其地址
汇编语言都一样,底层一样。
int main()
{
//引用语法层面:不开空间,是对其取别名
int& ra = a;
ra = 20;
//指针语法层面:开空间,存储其地址
int* pa = &a;
*pa = 30;
}
引用和指针的不同点:
(1)引用概念上定义一个变量的别名,指针存储一个变量地址。
更多推荐

所有评论(0)