命名空间namespace
命名空间像是开一个独立的小房间,虽然独立于全局域和局部域之外,但是它实际上还是个全局域,这样我们可以更具独立性的访问一些变量。 这里就需要用到域访问操作符了。
域访问操作符 ::
域访问操作符的左边一般是跟我们的命名空间,如果不跟则默认是全局域。右边则是跟我们的成员。
相较于C语言的printf函数来说,cout最大的优势就是自动匹配类型,省去了%d之类的东西
,也不需要在某处类型更改以后回头来改。
缺省值
同时函数还提供缺省值这一便利,我们可以预设参数,如果我们不传,那就用我们预设的,如果我们传了,那就用我们传的。缺省值也分全缺省和半缺省,全缺省不必多说,就是全给预设的数值,
而半缺省有一些需要注意的问题,给的缺省值必须从右往左,不能出现中间断开或者前有后没有的情况。
namespace yyy
{
int rand = 0;
int sub(int a = 1, int b = 2)//全缺省 如果给值 就按给的 否则就按默认的
{
return a - b;
}
int add(int a , int b=2) //半缺省值 必须从右往左
{
return a + b;
}
}
函数重载
C艹也给函数提供了另一项便利,有的时候我们可能会遇到功能一样但是类型或者参数不一样的函数,又因为C语言函数名唯一的特性,可能会搞得很麻烦,代码一多可能就忘了,所以C艹提供了重载功能。
我们可以返回类型一样,函数名一样,参数可以不一样或者顺序不一样就能达成重载,这样调用的时候,它会自动找到匹配的那一个运行。
//重载
void funcadd(int a, int b)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
void funcadd(double a, double b)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
//函数名可以一样 但是参数类型不能一样 避免出现同时满足两个函数的条件的情况
//但是可以交换参数类型 但是函数返回值的不同不能构成重载
引用
C语言中,大多数时候想要形参影响实参都需要指针,但是祖师爷好像并不喜欢指针,所以他来了个引用,引用就像是给人取了个小名,叫他名字他会回头,叫他小名也会回头。
void swap(int& x1 ,int& x2)//由于引用的关系 我们不再需要传指针 不需要注意实参与形参
{
int tmp = x1;
x1 = x2;
x2 = tmp;
}
int main()
{
//引用的概念
int a = 0;
//此时b其实就是a 改变b就会改变a 类似于给a起了个别名
int& b = a;
int x = 0, y = 1;
swap(x, y);
return 0;
}
它的符号就是& 只不过这次被类型牛走了,它不再跟着参数了。不过最好还是用它来顶替一下指针
,这里是因为xy生命周期在main函数结束,如果你想让swap里的内容以别名的形式出来可能会出问题,因为它的生命周期结束了,虽然引用确实能给你返,不过这就像野指针一样是不安全的。
虽然我不推荐,但是我还是给出写法
int& fun()
{
int ret = 0;
ret++;
return ret;
}
没错引用还能这么写,这里我们先明白,函数出了作用域就销毁,所以它其实是创建了一个临时变量存数据,返回的其实是这个临时变量。如果我们不引用,那一销毁谁也找不着了,而这里的引用,则是对这里的临时变量引用,所以我们还能找到它,但是它都销毁了,你找它反而可能出事,所以不要这么用它。
同时
int main()
{
int a = 0;
int& b = a;
int& c = a;
//引用也可以被引用
int& d = b;
int x = 1;
b = x;
//这样表面上看只改了个b 实际上abcd的指向都会被改变
return 0;
}
引用也有权限之分,如果一个正常的变量,我们不想它被动或者主动被改变,那么我们可以叫上const来限制,这就是权限的缩小,或者一个const变量,我们用const引用,这是权限的平移。
但是不能const变量用非const引用,因为不能权限放大。
//常引用
//int main()
//{
// //对应引用来说 它的权限是可以下放的 但是不能提升
// int a = 0;
// const int& b = a;//这样是可以的 这属于权限的缩小
// //此时a 可以修改 但是b不可以修改 而a的修改也会影响到b
//
//
// const int c = 0;
// int e = c;//这是赋值 并不存在放大缩小的问题
// const int& d = c;//这属于权限的平移 也是可以的 但是绝对不能放大 比如c是const但是d不是
//
//
// int j = 0;
// double k = j;//这是可以的
//
//
// //但是
// //double& l = j;//这样就不行 因为类型不同产生不管隐式类型或者显视类型转换都会创建临时变量 而临时变量具有常性
// //所以这里其实是一种权限放大
// const double& i = j;//这样就可以了 因为我们给了一个限制
//
//
//
//
//
// return 0;
//}
内联函数
学过C语言咱都知道宏虽然好用,但是容易出问题,所以我们保持敬而远之的态度,祖师爷偏不,他要改造一下,于是就有了内联函数 inline。
#define ADD(x,y) ((x)+(y))//宏函数 优点是不创建栈帧并且很快 缺点是写法很容易出错
//内联函数
inline int add(int x, int y)//inline
{
return x + y;
}
内联函数 类似于你提交一个申请 希望它就地展开算完 但是系统会判定
如果你的函数很长 或者是递归 那么它就会拒绝内联 以正常的方式算 但是如果短 它就会就地展开直接算完 并且不创建栈帧
既避免宏的易错性 也利用到了它的快速 可以定义多个内联 也可以在一个内联里调用另一个内联 前提是够短
如果是长函数 它在100个地方调用 那么内联函数如果展开就会在100个地方展开 那就会造成函数膨胀 空间大大浪费
所以只能短函数内联 又所以 内联一般的使用场景和宏一样 都适用于短小精干但是又需要一直调用的函数,为了节省时间和空间才采取内联的方式
同时 inline内联函数时 不能声明和主体分开 因为inline是就地展开的 如果声明和主体分开 那它在声明展开时啥也找不到 会产生链接错误