c++函数,函数重载,函数模板

2018-07-07 16:28:26

函数重载

函数重载的关键是函数的参数列表。如果两个函数的参数 数目和类型相同,同时参数的排列顺序也相同,则它们的特征标相同,而变量名是无关紧要的。C++允许 定义名称相同的函数,条件是它们的特征标不同。如果参数数目和或参数类型不同,则特征标也不同。例如,可以定义一组原型如下的 print()函数。

void print(const char * str, int width); // #1
void print(double d, int width); // #2
void print(long l, int width); // #3
void print(int i, int width); // #4
void print(const char *str); // #5


print("Pancakes", 15);     // use #1
print("Syrup");         // use #5
print(1999.0, 10);     // use #2
print(1999, 12);     // use #4
print(1999L, 15);     // use #3


void dribble(char * bits);
void dribble (const char *cbits);
void dabble(char * bits);
void drivel(const char * bits);

const char p1[20] = "How's the weather?";
char p2[20] = "How's business?";

dribble(p1);     // dribble(const char *);
dribble(p2);     // dribble(char *);
dabble(p1);     // no match
dabble(p2);     // dabble(char *);
drivel(p1);     // drivel(const char *);
drivel(p2);     // drivel(const char *);

从上面可以看出,非 const 传递给 const 是合法的。


函数模板

1.同一种算法应用到不同类型的函数,就用模板
2.不考虑向后兼容就用 typename 而不是 class
3.用模板就是编译器帮你生成多个函数
4.优先级--非模板函数 > 显式具体化 > 模板函数
5.函数重载-编译器通过参数决定使用哪个函数--重载解析

template <typename AnyType>
void Swap(AnyType &a, AnyType &b)
{
    AnyType temp;
    temp = a;
    a = b;
    b = temp;
}

以前老的代码里一般会用到 class 关键字,但是如果不考虑向后兼容,尽量使用 typename 而不是 class。

template <class AnyType>
void Swap(AnyType &a, AnyType &b)
{
    AnyType temp;
    temp = a;
    a = b;
    b = temp;
}

模板也能重载如

template <typename T>   // orginal template
void Swap(T &a, T &b);

template <typename T>   // new template
void Swap(T *a, T *b, int n);

1.所有让编译器通过传进来的参数来决定用哪个模板的都是隐性实例化
2.显示实例化是编译器直接生成函数定义,那么下次调用时候直接用,无需根据参数来判断

//显式具体化申明-在实际调用时候才生成函数
template <> void swap<string>(string &j1, string &j2){}
template <> void swap(string &j1, string &j2){}

//显示实例化声明-编译器直接生成函数
template void swap<int>(int,int);
swap(1,3)         //直接调用函数

//显式实例化调用-这样就无需-显示实例化声明
swap<int>(c,d)  //显式调用int模板

swap(c,d)       //有非模板函数则调用非模板函数
swap<>(c,d)     //从模板里选择
swap<int>(c,d)
#include <iostream>

template<class T>   // or template <typename T>
T lesser(T a, T b)          // #1
{
    return a < b ? a : b;
}

int lesser(int a, int b)    // #2
{
    a = a < 0 ? -a : a;
    b = b < 0 ? -b : b;
    return a < b ? a : b;
}

int main()
{
    using namespace std;
    int m = 20;
    int n = -30;
    double x = 15.5;
    double y = 25.9;

    cout << lesser(m, n) << endl;     // use #2
    cout << lesser(x, y) << endl;     // use #1 with double
    cout << lesser<>(m,n) << endl;    // use #1 with int
    cout << lesser<int>(x,y) << endl; // use #1 with int

    return 0;
}
#include <iostream>

template <typename T>
void Swap(T &a, T &b);

struct job
{
    char name[40];
    double salary;
    int floor;
};

// 显示具体化
template <> void Swap<job>(job &j1, job &j2);

void Show(job &j);

int main()
{
    using namespace std;
    cout.precision(2);
    cout.setf(ios::fixed, ios::floatfield);
    int i = 10, j = 20;
    cout << "i, j = " << i << ", " << j << ".\n";
    cout << "Using compiler-generated int swapper:\n";
    Swap(i,j);      // generates void Swap(int &, int &)
    cout << "Now i, j = " << i << ", " << j << ".\n";

    job sue = {"Susan Yaffee", 73000.60, 7};
    job sidney = {"Sidney Taffee", 78060.72, 9};
    cout << "Before job swapping:\n";
    Show(sue);
    Show(sidney);
    Swap(sue, sidney);  // uses void Swap(job &, job &)
    cout << "After job swapping:\n";
    Show(sue);
    Show(sidney);
    // cin.get();
    return 0;
}

template <typename T>
void Swap(T &a, T &b)       // general version
{
    T temp;
    temp = a;
    a = b;
    b = temp;
}

//显式具体化
template <> void Swap<job>(job &j1, job &j2)
{
    double t1;
    int t2;
    t1 = j1.salary;
    j1.salary = j2.salary;
    j2.salary = t1;
    t2 = j1.floor;
    j1.floor = j2.floor;
    j2.floor = t2;
}

void Show(job &j)
{
    using namespace std;
    cout << j.name << ": $" << j.salary
         << " on floor " << j.floor << endl;
}

c++11的 decltype 可以提供了自动判断类型并声明。

int x;
decltype(x) y; // y类型等同于x

decltype(x + y) xpy; // xpy等同于x+y类型
xpy = x + y;

#也可以一句话
decltype(x + y) xpy = x + y;

#那么模板也可以写成这样
template<class T1, class T2>
void ft(T1 x, T2 y)
{
...
decltype(x + y) xpy = x + y;
...
}

decltype 实际上最多要经历4步来判断类型。

1.如果 expression 是一个没有括号的标识符,则 var 的类型与标识符的类型相同,包括 const。

int x;
decltype(x) y;  //int

2.如果 expression 是一个函数调用,则 var 的类型与函数的返回值相同。

long freecls(int);

#long
decltype(freecls(3)) x = 4;

3.如果有括号,那么会经历第1步和第3步。

int x = 4;

//此时 y 是x的引用
decltype((x)) y = x;

//相当于
int &y = x;

4.如果上面3个都不满足,那么 var 类型与 expression 的类型相同。

int j = 3;
int &k = j
int &n = j;
decltype(j+6) i1;  // i1 type int
decltype(100L) i2; // i2 type long
decltype(k+n) i3;  // i3 type int;

虽然 k,n 都为引用,但是它们相加不是引用。如果需要多次声明,可结合 typedef。

template<class T1, class T2>
void ft(T1 x, T2 y)
{
...
typedef decltype(x + y) xytype;
xytype xpy = x + y;
xytype arr[10];
xytype & rxy = arr[2]; // rxy a reference
...
}

c++11后置返回类型

下面这样的实现是错误的,因为在使用 decltype(x + y)时,x,y并没有定义。

template<class T1, class T2>
decltype(x + y) gt(T1 x, T2 y)
{
...
return x + y;
}

后置返回类型语法如下,auto配合 ->。

#表明返回值类型为 double
auto h(int x, float y) -> double
{/* function body */};

我们在模板里就可以利用 decltype 来指定返回类型,因为decltype 在x,y声明后面,所以可以使用它们。

template<class T1, class T2>
auto gt(T1 x, T2 y) -> decltype(x + y)
{
...
return x + y;
}
©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。