本文主要讲解C++解决了C语言哪些语法的不足,C++是如何改进的。
C语言中,会遇到两种情况的命名冲突,分别是
注意C语言无法解决命名冲突的问题。
C++解决方法:
运用命名空间关键字:namespace
下面的代码表示rand变量与库函数stdlib中的rand函数命名冲突,我们运用namespace命名空间。
相当于在rand = 0围上了一圈栅栏,默认不访问栅栏里面的内容,从其他全局域寻找。
当我们使用::域作用限定符,相当于钥匙打开了栅栏,我们就从栅栏里面的内容寻找。
#include
#include
namespace wh
{
int rand = 0;//rand还是全局变量
}
int main()
{
printf("%p", rand);//表示rand这个函数
printf("%d", wh::rand);//::域作用限定符,表示我们自己定义的rand变量
return 0;
}
我们平时定义的所有变量都可以在命名空间中定义,注意结构体语法形式有点不同
命名空间可以套娃!
命名空间在多个文件中可以合并,所以不必考虑多个相同的命名空间回重复。
但有时命名空间也是累赘,比如自己写好做测试,没有给别人用,不存在命名冲突,我们每次调用变量、函数都需要加上命名空间吗?
就需要展开命名空间,这样每次调用就不用加上命名空间。
所以我们就理解了
using namespace std
这是C++官方库定义的命名空间,里面包含了cout、cin等等。
工程项目不要展开std,容易冲突。
但是日常练习,为了方便就可以展开
命名空间的另一种玩法:
每次指定命名空间很不方便,直接展开全部暴露,又有命名冲突的风险
我们采用指定展开可以解决问题。
缺省参数是声明或定义函数时为函数参数指定一个缺省值。
在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
我们做人不能做缺省参数(舔狗),女神没有对象时请你看电影,用缺省参数,但如果有对象,直接就不用你了,用自己的参数,不用缺省参数。
缺省参数分类:
函数中的所有参数都带有缺省值,在调用时不能隔着传参。
函数中参数并不完全带有缺省值。
C语言不支持同名函数。
是函数的一种特殊情况,C++允许在同一作用域中声明几个功能相似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或类型顺序)不同,返回值无关。
因为当你调用两个返回值不同的重载的函数,如果参数都相同,不能根据返回的不同确定到底调用哪个函数。
C语言链接函数地址时,就用函数名去寻找,所以C语言不存在同名函数。
但在C++中,运用了函数名修改规则
_Z 函数名字符个数 函数名 参数首字母
当函数只有声明,没有定义,会在链接时候报错,链接的意义是链接一些没有确定函数地址
引用不是新定义一个变量,而是给已存在变量取了一个别名,引用的变量和本身变量共用同一块空间。引用就是取别名。
经典例子,在单链表中尾插,如果链表为空,需要改变头节点,这时候就要用到二级指针去改变正在指向的内容,但如果引用结点指针的变量,不需要指针即可。
答案肯定是不可以。
引用的注意点:
1、引用必须初始化。
2、C语言引用不能改变指向。
上述代码表示d赋值给c,c是a的别名,c = d表示赋值,不是变成d的别名,因为在C语言中引用不能改变指向。
这也就验证了C++中,引用不能替代指针,在Java语言中,引用是可以改变指向的,所以在链表中,如果用引用表示next指针,Java可以改变指向,指向另一个结点,在C++中就不行,因此C++中引用和指针是相互配合的关系。
3、一个对象可以有多个别名
上面count函数返回值是n吗?
不是,返回值是n的拷贝。
为何?
因为函数栈帧在调用后回自动销毁,所以count函数会自动销毁,n也会销毁,所以我们返回的是n的拷贝,不属于count函数空间里面的内存
如果是传引用返回,打印的结果是不确定的。
因为返回引用n就是n的别名,也就是n本身,为何不确定,因为不确定编译器在count调用后(栈帧结束)是否清理空间,如果空间不清理,就是n,如果清理了就是随机值。
引用返回和静态变量结合,(出函数作用域不会销毁的变量,不是在栈空间上创建的变量)。
ret就是c的别名,两者相同
输出结果是3,3
为何不是3,7?
因为局部的静态变量只会初始化一次!
这样的输出结果就是3,7!
传值返回时,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回类型,效率是非常地下的,尤其是当参数或者返回值类型非常大时,效率就更低。
引用返回的总结:
出了函数作用域,返回对象就销毁了,不能用引用返回,否则结果是不确定的。只有返回值在出函数作用域之后还在,才能用引用返回!
在使用上和概念上的区别
在语法上,引用没有开辟空间,但是指针开辟空间
在底层汇编语言上。两者原理是一样的。
因为在C语言中,宏的缺点太多!
宏本质上是替换!
#define Add(x,y) ((x) + (y))//容易出错
int main()
{
int sum = Add(3, 2);
printf("%d", sum);
return 0;
}
注意宏每个括号的含义,应对运算符优先级的问题。并且不能有;,因为宏是表达式的替换
不用建立栈帧,提升程序运行的效率。普通函数使用时,需要建立栈帧,而栈帧的建立是非常繁琐的。
因为宏函数缺点较多,所以C++在此基础上应运而生了内联函数。
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。
内联函数的优点不仅包含了宏函数的缺点,还不用创建栈帧,如此优秀的机制,
内联函数只适用于函数代码量较小的情况下(低于10行)。
因为如果函数调用次数过多,每次都要展开,会使得程序量变大(很坏)。
而普通的函数调用只需要一行调用指令即可。
注意内联函数不能声明和定义分离(不能在一个文件定义,在另一个文件声明),
因为内联函数被展开,就没有函数地址了,链接就会找不到。