1. 为什么C语言不能支持函数重载呢?
什么是函数重载呢? 函数重载是函数的一种特殊情况,在同一作用域中声明几个功能类似的同名函数,这些函数的形参列表(类型,个数,顺序)必须不同。
知道了函数重载的概念,那么我们就要知道c语言的编译的时候是如何处理函数的,首先我们要编译C风格的代码,我们需要让某些函数以C的方式编译,在函数前面加上 extern "C" ,此时编译器就以c的风格来进行编译,那么我们会发现,c方式在编译的时候,他是将函数解析成_函数名的格式,因此若出现同样的函数名,编译器无法区分,就会报错
extern "C" int add(int a, int b);
int main(){
add(10, 20);
}
2.c++是如何实现函数重载的?
这里我们再来了解一个叫“名字修饰”的概念:是在函数编译的过程中,是将函数,变量的名称重新改编的机制,也就是编译器为了区分各个函数,将函数通过一定的算法,重新生成一个全局的唯一的名称。
我们可以看到,函数在底层使用的其实不是函数的add名字,而是被重新修饰过得一个复杂的名字,被重新修饰的名字包括了:函数名字和类型。这就是为什么c++函数重载几个相同名字的函数要求其参数列表不同的原因,只要参数列表不同,经过一系列的修饰之后,就可以变成一个全局唯一的名字
3.关于引用
引用概念:引用不是新定义一个变量,而是给已存在变量取一个别名,编译器不会为引用变量开辟空间,他和引用变量共用一块内存空间。
*int a = 10;
int& ra = a;
引用类型必须和实体类型一致
常引用:
const int a = 10;
int& ra = a;//不可以
const int& ra = a;
const int&ra = 20;
引用的使用场景:
可以作为参数和返回值。
传引用就不存在值拷贝,他是直接用的引用的实体来进行的数据运算
//void swap(int& a, int& b){
// int tmp = a;
// a = b;
// b=tmp;
//}
//int& test1(int& a)
//{
// a += 10;
// return a;
//}
//传引用 作为形参
/*int a = 10;
int b = 20;
swap(a, b);*/
//作为返回值
/*int a = 10;
test1(a);*/
但不可以返回栈上的引用
若返回栈上的引用存在隐患,返回值为栈上的引用,函数调用完成,栈空间释放,所以之后谁都可以覆盖此处空间的
int& add1(int a , int b){
int c= a + b;
return c;
}
int& sum = add1(10, 20);
cout <<"add1(a,b)="<< sum;
add1(100, 200);
cout <<"add1(a,b)="<< sum;
此时返回c的引用,是在栈上的一个空间,所以在调用一次add,但没有将其值赋值给sum,在此输出,就会变成300.
对于传值,传址,传引用,那个效率更高呢?
经过测试我们发现,传址和传引用几乎一样,那么这又是为什么?
我们其实引用在底层实现和指针是一摸一样的。
那么他们两个有什么区别呢?
1.引用在定义的时候必须初始化,而指针不作要求
2.引用在初始化时引用了一个实体,之后就不能在引用别的实体,而指针可以在任何时候指向任何一个同一类型的实体
3.没有NULL引用,但有NULL指针
4.sizeof的含义不用,引用结果为引用类型的大小,而指针始终是地址空间所占的字节数,在32位平台下是4个字节
5.引用自加1即实体加1,但指针+1是向后偏移一个类型的大小
6.有多级指针但没有多级引用
7.访问实体方式不同,指针需要解引用,而引用会由编译器完成
8.引用比指针更安全
4.内联函数
以inline修饰的函数叫内联函数,编译时,c++会在调用内联函数的地方展开,没有函数压栈的开销,提高了效率
特点:
inline是一种以时间换空间的做法,所以代码很长或有递归则不适合。
inline对于编译器只是一种建议,编译器会自动优化,若函数内部有递归或循环,则会忽略掉inline
我们发现inline和宏非常类似,那么对于宏的优缺点是什么呢?
优点:
1.提高性能
2.曾倩代码复用性
缺点:
1.可读性差
2.无类型检查
3.不可调式