(1)连接指示符:通知编译器,某个函数是由其它语言编写的。
语法:
1. extern "语言名" 函数原型;
2. extern "语言名"
{
函数原型1;
...
函数原型n;
}
3.extern "语言名"
{
include 文件名
}
原因:C++语言编译器会对函数重载进行重命名(Name-Mangling);但是在C语言中,由于不允许出现同名的全局函数(静态全局函数除外),不需进行重命名。所以在程序中如果出现了extern "C" fun(int);就不应出现extern "C" fun(double);
例如:
extern "C" fun(int);
extern "C" fun(double);
int main(void)
{
fun(3);
fun(3.5);
return 0;
}
error C2733: second C linkage of overloaded function 'fun' not allowed
(2)函数重载的解析
根据函数调用中的实参,确定要执行的函数。
结果:
1.没有函数可调用(出错);
2.恰有一个可调用;
3.有多个可调用,二义性(在编译时发现)。
解析的时机:
1.函数调用时解析;
例如:
void fun(long);
void fun(int);
求:fun(3);
2.取函数地址。
例如:
void g(void (*fp)(long));
void g(void (*fp)(int));
求:g(f);
(3)实参类型转换
1.精确匹配。包含4种情形(其中a,b.c称为左值转换):
a.从左值到右值的转换
b.从数组到指针的转换
c.从函数到指针的转换
例如: int fun(int);
void g(int (*fp)(int));
求:g(fun);
d.限定修饰符转换
例如:int *q;
void fun(const int * p);
求:fun(q);
2.提升
a.带符号或不带符号的char,short类型转换为int型。
b.float => double
c.bool => int
3.标准转换
a.算术类型间的转换,这与提升a,b是一样的。
b.整型0到各种指针;各种指针 => void *
c.各种算术指针 => bool
4.用户自定义转换
标准转换序列:
0个或1个左值转换 -> 0个或1个提升或标准转换 -> 0个或1个限定修饰符转换
重载函数解析的过程:
1.确定候选函数集
a.调用点可见的同名函数
b.实参类型定义所属名字空间中的同名函数
2.确定可行函数集
a.实参个数 <= 形参个数,形参多出的必有缺省值。
b.有实参到形参的转换序列。
3.确定最佳可行函数。
(4)函数模板
1.功能不同或者是功能太大时不要使用函数重载。
所谓函数重载,是指自动生成各种类型函数的算法。
定义语法:template <模板参数表>
值类型 函数名 (形参表)
函数体
模板参数,由两类参数构成:
a.模板类型参数
声明方式: typename 标识符
表示一个特定类型。
b.模板非类型参数
声明方式: 通常的变量声明
表示一个值。
说明:
值类型,可以是内置类型,用户定义类型,模板类型参数
形参表,允许类型如上
函数表,定义的局部变量类型如上。
例如:
#include <iostream>
using namespace std;
template <typename T, int size>
T min(T (&a)[size])
{
int i;
T x = a[0];
for(i = 0; i < size; i++)
{
if (x > a[i])
x = a[i];
}
return x;
}
template <typename T>
T min(T *a, int size)
{
int i;
T x = a[0];
for(i = 0; i < size; i++)
{
if (x > a[i])
x = a[i];
}
return x;
}
int main()
{
int a[] = {1, 2, 3, -1, 5, 2, 4};
cout << min(a) << endl;
cout << min(a, 7) << endl;
}
模板实例化:
根据函数调用,自动生成函数。
说明:
显示指定模板参数语法:
函数名<实参名, ..., 实参名>(实参表);
例如:
template <typename T1, typename T2, typename T3>
T1 fun(T2 x, T3 y)
{
...
}
fun<int, int, double>(3, 2.5);
函数实参推演:从函数调用的实参确定模板参数的过程。
模板特化语法:
template <>
值类型 函数名<实际模板参数值>(形参表)
函数体
举例略。
函数模板的重载:
1.求候选函数集,较为复杂,略。
2.求可行函数集
3.最佳可行函数集
在写函数模板时,可以先写好特殊类型下的,再写一般的。例如:排序函数模板程序如下。
#include <iostream>
using namespace std;
template <typename T>
void sort(T *array, int n)
{
cout << "sort in template 1..." << endl;
//下标
int i, j;
//暂存待排序元素
T tmp;
for(i = 1; i < n; i++)
{
tmp = array[i];
j = i - 1;
//寻找插入位置
while(j >= 0 && array[j] > tmp)
{
array[j + 1] = array[j];
j--;
}
array[j + 1] = tmp;
}
}
template <typename T1, typename T2>
void sort(T1 *array, int n, T2 fun)
{
cout << "sort in template 2..." << endl;
//下标
int i, j;
//暂存待排序元素
T1 tmp;
for(i = 1; i < n; i++)
{
tmp = array[i];
j = i - 1;
//寻找插入位置
while(j >= 0 && fun(array[j], tmp))
{
array[j + 1] = array[j];
j--;
}
array[j + 1] = tmp;
}
}
int cmp(int a, int b)
{
return a > b;
}
int main()
{
int a[] = {1, 3, 5, 8, 9, 4, 6, 7, 2};
int size = sizeof(a) / sizeof(int);
sort(a, size);
for(int i = 0; i < size; i ++)
{
cout << a[i] << endl;
}
cout << endl;
sort(a, size, cmp);
for(int i = 0; i < size; i ++)
{
cout << a[i] << endl;
}
cout << endl;
double b[] = {1.0, 3.0, 5.0, 8.0, 9.0, 4.0, 6.0, 7.0, 2.0};
int dsize = sizeof(b) / sizeof(double);
sort(b, dsize);
for(int j = 0; j < dsize; j++)
{
cout << b[j] << endl;
}
cout << endl;
sort(b, dsize, cmp);
for(int j = 0; j < dsize; j++)
{
cout << b[j] << endl;
}
}
<补充>
1.确定候选函数集
a.调用点可见的同名函数
b.实参类型定义所属名字空间中的同名函数
对于b项,老师举例:
namespace N
{
class A{};
void f(A x){};
void f(int){};
}
void f(double){}
int main()
{
N::A x;
f(x);
}