王老师 C++ 函数重载和模板 第二讲

(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);
}

你可能感兴趣的:(C++,语言,iostream,FP,编译器,fun)