一、函数重载
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
理论看一遍就行啦,还是直接上栗子好理解吧!
🌰栗子
1.1 函数参数类型不同
//函数参数类型不同 #include <iostream> #include <stdio.h> //展开部分常用的 using std::cout; using std::cin; using std::endl; namespace cjn { //函数1 int add(int e1, int e2) { cout << "整形:"; return e1 + e2; } //函数2 double add(double e1, double e2) { cout << "浮点形:"; return e1 + e2; } } int main() { int a = 0, b = 0; double c = 0, d = 0; cin >> a >> b; //a和b是int型,会调用int add(int e1, int e2)函数 cout << cjn::add(a, b) << endl; cin >> c >> d; //c和d是double型,会调用double add(double e1, double e2) cout << cjn::add(c, d) << endl; return 0; }
输入:
2 3
3.4 5.2
输出
整形:5
浮点形:8.6
函数1和函数2虽然函数名相同,但是函数的参数不同,构成函数重载.
1.2 函数参数的个数不同
🌰栗子
//函数参数个数不同时 #include <iostream> #include <stdio.h> using std::cout; using std::cin; using std::endl; namespace cjn { void fun() //函数1 { cout << "fun()" << endl; } void fun(int a) //函数2 { cout << "fun(int a)" << endl; } } int main() { cjn::fun(); //会调用函数1 cjn::fun(0); //会调用函数2 return 0; }
运行结果:
fun()
fun(int a)
此时还有一个特殊情况:
namespace cjn { void fun() //函数1 { cout << "fun()" << endl; } void fun(int a=4) //函数2 { cout << "fun(int a)" << endl; } } int main() { cjn::fun();//此时编译器不知道应该调用哪一个函数 return 0; }
分析:
由于函数2设置了缺省值,所以在不传参时,会产生混乱.
1.3 函数参数顺序不同
🌰栗子
//函数参数顺序不同 #include <iostream> #include <stdio.h> using std::cout; using std::cin; using std::endl; namespace cjn { void fun(int a,char b) //函数1 { cout << "fun(int a,char b)" << endl; } void fun(char a,int b) //函数2 { cout << "fun(char a,int b)" << endl; } } int main() { cjn::fun(1,'c'); //会调用函数1 cjn::fun('a',0); //会调用函数2 return 0; }
运行结果:
fun(int a,char b)
fun(char a,int b)
1.4 不构成函数重载
函数的返回值不同 :不构成函数重载
//不支持函数重载 namespace cjn { int fun(char a,int b) //函数1 { cout << "fun(int a,char b)" << endl; } double fun(char a,int b) //函数2 { cout << "fun(char a,int b)" << endl; } }
为什么C不支持函数重载,而C++支持?(重点)
上面也说了,返回值不同也不支持函数重载,让我们从底层来揭秘吧!
在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。这些在C语言中的程序环境阶段有细讲.
我们知道,如果我们只有函数的声明,相当于只拿到了承诺,具体的函数定义并没有拿到,要在最后的链接阶段去通过符号表(很重要)拿到函数地址(兑现承诺).
而符号表中对于函数名的修饰规则在C和C++中是不同的.
例如:
//以下列函数为例 int Add(int a, double b) { ...... } void Swap(double* e1, double* e2) { double tmp = *e1; *e1 = *e2; *e2 = tmp; }
由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下图是g++修饰后的名字规则。
C语言和C++的函数名修饰的不同
在C语言中,只是简单的将函数名直接存入符号表,而C++则考虑到函数的参数类型,函数名长度等因素.
而g++环境下的C++中的函数修饰后变成【_Z+函数长度+函数名+类型首字母】
疑问:如果两个函数函数名和参数是一样的,返回值不同构成函数重载吗?
示例:
int add(int a, int b) { ; } double add(int a, int b) { ; } int main() { add(2, 3);//调用哪个函数?返回值没有体现也无法体现在调用处 return 0; }
答案是:不构成函数重载,即使修改了底层函数名修饰规则也不行,因为在调用函数时,返回值无法体现,无法区分该调用哪个函数.
1.5 “extern C”
由于C和C++编译器对函数名字修饰规则的不同,在有些场景下可能就会出问题,比如:
情况1:
C++中调用C语言实现的静态库或者动态库,反之亦然
情况2:
多人协同开发时,有些人擅长用C语言,有些人擅长用C++
在这种混合模式下开发,由于C和C++编译器对函数名字修饰规则不同,可能就会导致链接失败,在该种场景下,就需要使用extern “C”。在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译。
🌰栗子:
为了能在C/C++工程中都能使用,函数声明时需加上extern “C”
#ifdef __cplusplus//如果是c++项目(这里要求用c语言实现) extern "C"//此时这条语句会执行 { #endif int Add(int left, int right); int Sub(int left, int right); #ifdef __cplusplus } #endif
解释:
#ifdef _cplusplus
}
#endif
作用:
(1):c++工程中保证是以C的方式实现
_如果是C++工程,编译器已经定义_cplusplus宏,编译时该宏是可以被识别的,被声明的函数就被extern "C"修饰了,此时C++编译就知道,该函数是按照C的方式编译的,这样在链接时就会按照C的方式找函数名字.
(2):C工程中不受影响
如果是C工程,编译器未定义_cplusplus宏,编译时该宏无法被是被,则条件编译就无效,函数就不会被extern "C"修饰 .
二、引用
引入:
C指针玩法:
在C语言阶段,我们可以通过一个指针去找变量,指针就好比是老板的秘书(一级指针),老板太忙了,只给秘书(一级指针)留了联系方式,我们可以通过秘书(一级指针)去找变量,如果秘书(一级指针)也比较忙,就会给秘书也会自己的秘书留下联系方式,即秘书的秘书(二级指针).
C++引用玩法:
例如:有个小女孩真名叫“涂山苏苏”,我们也可以叫她“小蠢货”,”蠢货苏”等别名,或者“苏苏”等其它小名.这些名词虽然不一样,但是代表的内容都是“涂山苏苏”本人,这便是C++引用的做法,取别名.
图解:
示例代码:
# include <iostream> using std::cout; using std::cin; using std::endl; int main() { int a = 5; //下面都是对a的引用,即a的别名. int& b = a; int& c = a; int& d = a; int& e = a; cout << a << " " << b << " " << c << " " << d << " " << e << endl; return 0; }
运行结果:
5 5 5 5 5
2.1 引用特点:
- 引用必须初始化.
int main() { int a = 5; //如果我们引用不初始化 int& b; return 0; }
改代码会显示错误信息:
这也很好理解,引用就类似与取别名,如果连对象都没有,那别名还有啥意义.
- 引用一旦确定了引用实体后,就不能像指针一样改变指向了.
int main() { int a = 5; int c = 1; int& b=a; b = c;//这样b就是c的别名了吗? cout << a << " " << b << " " << c << endl; return 0; }
运行结果:
1 1 1
b=c并不是将b改为c的别名,而是赋值,将b的值给改了,b改了,那也就等于a也改了.