C++ 第二篇
c++ 函数
1. 函数重载
1.1 定义
在相同的作用域中,定义同名函数,但是他们的参数必须有所区别。这样的函数构成重载关系。
注意: 函数重载与返回值的类型无关
1.2 函数重载匹配
调用重载函数时,编译器会根据实参和形参的匹配程度,自动选择最优的重载版本。
当前 g++ 编译器的匹配原则:
完全匹配 >= 常量转换> 升级转换 > 降级转换 > 省略号匹配
对于 char --> cons char 这种没有 区别
对于 char * —> cons char * 此时 完全匹配好于常量转换
#include <iostream>
using namespace std;
int foo(int i)
{
cout <<"foo(int)"<< endl;
}
void foo (int i, int j)
{
cout<< "foo(int,int)"<< endl;
}
void foo (int i, float j)
{
cout<< "foo(int,float)"<< endl;
}
int main(void)
{
foo(1,2);
foo(1);
foo(1,2.34f);
// 在匹配函数指针时,匹配的是foo(int,float). 因此该函数指针指向这个函数。
void (*pfoo)(int i, float j) = foo;
pfoo(100,200); // 调用的是 foo(int,float)
return 0;
}
重载匹配的其他情况
#include <iostream>
using namespace std;
// char --> int 升级转换
void bar(int i)
{
cout << "bar(int)"<< endl;
}
// char ---> const char 常量转换
void bar(const char c)
{
cout <<"bar (const char)"<< endl;
}
// short --> int 升级转换
void hum(int i)
{
cout <<"hum(int)" << endl;
}
// short --> char 降级转换
void hum(char c)
{
cout << "hum(char)"<< endl;
}
// 省略号匹配 (无奈的办法)
void func(int i, ...)
{
cout << "func(int,...)"<< endl;
}
// double ---> int 降级转换
void func(int i, int j)
{
cout << "func(int, int)"<< endl;
}
int main(void)
{
char c = 'a';
bar(c); // bar (const char)
short s = 10;
hum(s); // hum(int)
func(100,23.32); // func(int ,int)
return 0;
}
1.3 c++ 重载原理
c++ 编译器会将函数进行换名,将参数的类型信息整合到新的函数名中。
g++ -C 02overload.c -o 02overload.o
nm 02overload.o 查看里面的函数名
发现
0000000000400969 T _Z4funcii
00000000004008f2 T _Z4funciz
对func 完成了换名字的操作
最后 ii 表示两个整形
iz 表示 int 和 …
二 c++ 中 extern “c”作用
函数声明前加入 extern “C”, 要求C++ 编译器按照c 语言的方式编译该函数,不对其进行换名,便于C程序调用该函数。
注意: 被 extern “C” 声明的函数是无法重载的。
c++ 代码:
#include <iostream>
using namespace std;
void hello(void)
{
cout << "hello"<< endl;
}
C 代码:
void hello (void);
int main()
{
hello();
return 0;
}
编译 :
gcc -c c.c
g++ -c cpp.cpp
g++ *.o
发现c 中的hello 找不到
原因 : c++ 在编译函数时,会有换名字的操作,因此在c 中找不到hello 函数
解决办法:
- 将c 中的函数名字修改为C++ 编译以后的函数名字 不推荐使用
void _Z5hellov (void);
int main()
{
_Z5hellov();
return 0;
}
- 在 c ++ 中hello 函数名前面加上extern “C”, 告诉编译器,将这个函数按照C 的风格进行编译。
#include <iostream>
using namespace std;
extern "C" void hello(void)
{
cout << "hello"<< endl;
}
三 函数的缺省值
函数的缺省值(默认参数)
3.1 可以为函数部分参数或者全部参数指定缺省值,调用该函数时,如果不给实参,则取缺省值作为默认实参。
void func(int a, int b = 0 /* 缺省参数*/) {}
3.2 缺省参数是靠右原则。如果一个函数的一个参数有缺省值,那么该参数的右侧的所有参数 都必须有缺省值。
3.3. 如果函数的定义和函数的声明分开写,缺省参数应该写在函数声明的部分,定义的部分不能写。
void func (…); // 函数声明
void func (…){ …} // 函数定义
void func(int a , int b = 20, int c = 30){}
void func (int a) // 函数重载,但是对单个参数传入的func(2),都可以匹配,会有歧义错误。
四 函数的哑元参数
4.1 定义函数时,只有类型,但是没有变量名,成为哑元参数。
void func (int /哑元/){
…
}
4.2 使用哑元的场景
–》》 操作符重载,用于区分 前后++, –
++a a++
–>> 为了兼容旧代码
五 内联函数
5.1 内联函数(inline)
使用inline 关键字修饰的函数,即为内联函数
编译器会尝试对内联函数 进行优化,可以减少函数调用的开销,提供代码的执行效率。
内联函数是在函数编译的时候,进行的替换。程序的内存会变大,但是没有函数调用的开销,因此效率提高。
5.2 使用说明
》需要多次调用的小而简单的函数适合作为内联函数。
》 调用次数极少,大而复杂的函数,不适合内联。
》 递归函数不能内联
》 虚函数不能内联 (由于在运行时才决定,因此不能替换)
注意: 内联知识一种建议,不是强制的要求,一个函数能否内联,主要取决于编译器,有一些函数不加inline修改,也会默认处理为内联优化。有些函数即使加了inline ,也会被编译器忽略。