文章目录
- 一、C++内联函数
- 二、引用变量:C++新增
- 2.将引用用作函数参数(引用用的最主要的方式)
- 3.引用的属性和特别之处
- (f)再次强调一下使用const的好处:尽可能地将引用声明为const
- 4.将引用用于结构
- 5.将引用用于类对象
- 6.对象、继承和引用
- 7.何时使用引用参数??
- 1.函数重载的例子
- 2.何时使用函数重载
- 1.函数模板的基本知识
- 2.重载模板
- 3.模板的局限性
- 4.显示具体化
- 5.实例化和具体化
- 6.编译器选择使用哪个函数版本
- 7.函数模板的发展(了解即可,decltype关键字实在看得太少了)
一、C++内联函数
(1)C++区别于C语言,提供了新特性:内联函数,引用传递变量,默认的参数值,函数重载(多态)以及模板函数;
(2)C++内联函数的优势:
(3)写内联函数的要求:
(a)在函数声明前加上关键字inline;
(b)在函数定义前加上关键字inline;
(c)内联函数不能递归
(4)什么时候用内联函数呢?
代码量不多,且经常使用
(5)eg如下:
#include<stdio.h>
#include<stdlib.h>
// inline.cpp -- using an inline function
#include <iostream>
// an inline function definition
inline double square(double x) { return x * x; }
int main()
{
using namespace std;
double a, b;
double c = 13.0;
a = square(5.0);
b = square(4.5 + 7.5); // can pass expressions
cout << "a = " << a << ", b = " << b << "\n";
cout << "c = " << c;
cout << ", c squared = " << square(c++) << "\n";
cout << "Now c = " << c << "\n";
system("pause");
return 0;
}
说明:
(1)
(2)内联函数与宏定义的区别
二、引用变量:C++新增
(1)引用变量的意思:
(2)创建引用变量:
(a)C和C++使用&符号来指示变量的地址。C++给&符号赋予了另一个含义,将其用来声明引用。
(b)eg1:
eg2:
#include<stdio.h>
#include<stdlib.h>
// firstref.cpp -- defining and using a reference
#include <iostream>
int main()
{
using namespace std;
int rats = 101;
int & rodents = rats; // rodents is a reference
cout << "rats = " << rats;
cout << ", rodents = " << rodents << endl;
rodents++;
cout << "rats = " << rats;
cout << ", rodents = " << rodents << endl;
// some implementations require type casting the following
// addresses to type unsigned
cout << "rats address = " << &rats;
cout << ", rodents address = " << &rodents << endl;
system("pause");
return 0;
}
说明:
(a) int & rodents = rats; // rodents is a reference
意思是:将rodents的类型声明为int &,即指向int变量的引用;
(b) cout << ", rodents address = " << &rodents << endl;
意思是:&运算符是地址运算符,其中&rodents表示rodents引用的变量的地址;
(c)引用和指针的区别如下:
相似点:
不同点:引用还是不同于指针的!
第一点:
必须在声明引用时将其初始化,而不能像指针那样,先申明,再赋值。
第二点:
(3)eg:
#include<stdio.h>
#include<stdlib.h>
// secref.cpp -- defining and using a reference
#include <iostream>
int main()
{
using namespace std;
int rats = 101;
int & rodents = rats; // rodents is a reference
cout << "rats = " << rats;
cout << ", rodents = " << rodents << endl;
cout << "rats address = " << &rats;
cout << ", rodents address = " << &rodents << endl;
int bunnies = 50;
rodents = bunnies; // can we change the reference?
cout << "bunnies = " << bunnies;
cout << ", rats = " << rats;
cout << ", rodents = " << rodents << endl;
cout << "bunnies address = " << &bunnies;
cout << ", rodents address = " << &rodents << endl;
system("pause");
return 0;
}
说明:
(a)
(b)指针和引用的小eg
2.将引用用作函数参数(引用用的最主要的方式)
(1)引用传递的含义以及对C语言的超越地方的说明
(2)按值传递和按指针传递的区别:
(3)交换两个变量的值,引用传递,使用指针和值传递之间的区别
具体eg如下所示:
#include<stdio.h>
#include<stdlib.h>
// swaps.cpp -- swapping with references and with pointers
#include <iostream>
void swapr(int & a, int & b); // a, b are aliases for ints
void swapp(int * p, int * q); // p, q are addresses of ints
void swapv(int a, int b); // a, b are new variables
int main()
{
using namespace std;
int wallet1 = 300;
int wallet2 = 350;
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
cout << "Using references to swap contents:\n";
swapr(wallet1, wallet2); // pass variables
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
cout << "Using pointers to swap contents again:\n";
swapp(&wallet1, &wallet2); // pass addresses of variables
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
cout << "Trying to use passing by value:\n";
swapv(wallet1, wallet2); // pass values of variables
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
system("pause");
return 0;
}
void swapr(int & a, int & b) // use references
{
int temp;
temp = a; // use a, b for values of variables
a = b;
b = temp;
}
void swapp(int * p, int * q) // use pointers
{
int temp;
temp = *p; // use *p, *q for values of variables
*p = *q;
*q = temp;
}
void swapv(int a, int b) // try using values
{
int temp;
temp = a; // use a, b for values of variables
a = b;
b = temp;
}
说明:
(a)引用传递和指针都成功的交换了两个wallet的内容,而值传递的方法没能完成这项任务。
(b)引用传递与值传递的区别如下:
(c)引用传递和指针传递的区别如下:
3.引用的属性和特别之处
(1)eg
#include<stdio.h>
#include<stdlib.h>
// cubes.cpp -- regular and reference arguments
#include <iostream>
double cube(double a);
double refcube(double &ra);
int main ()
{
using namespace std;
double x = 3.0;
cout << cube(x);
cout << " = cube of " << x << endl;
cout << refcube(x);
cout << " = cube of " << x << endl;
// cin.get();
system("pause");
return 0;
}
double cube(double a)
{
a *= a * a;
return a;
}
double refcube(double &ra)
{
ra *= ra * ra;
return ra;
}
说明:
(a)
(b)啥时候用值传递,啥时候用指针传递?
(c)传递引用限制更加严格
(d)如果写成如下的形式,注意体会在形参中使用const的感觉
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
// cubes.cpp -- regular and reference arguments
#include <iostream>
double cube(double a);
double refcube(const double &ra);
int main()
{
using namespace std;
double x = 3.0;
//double re;
cout << cube(x);
cout << " = cube of " << x << endl;
double re=refcube(x);
cout << re;
cout << " = cube of " <<x<< endl;
// cin.get();
cout<<"shazi"<<endl;
//system("pause");
return 0;
}
double cube(double a)
{
a *= a * a;
return a;
}
double refcube(const double &ra)
{
double res;
res=ra* ra * ra;
return res;
}
(2)临时变量、引用、const
(a)如果实参与引用参数不匹配,C++将生成临时变量;
(b)什么时候创建临时变量呢?
(c)什么是左值,非左值?
(d)eg:
说明:
(e)
(f)再次强调一下使用const的好处:尽可能地将引用声明为const
4.将引用用于结构
(1)使用引用主要是为了用于结构和类这些类型的,而不是基本的内置类型。
(2)在结构中如何使用引用?
eg1:
eg2:
#include<stdio.h>
#include<stdlib.h>
//strc_ref.cpp -- using structure references
#include <iostream>
#include <string>
struct free_throws
{
std::string name;
int made;
int attempts;
float percent;
};
void display(const free_throws & ft);
void set_pc(free_throws & ft);
free_throws & accumulate(free_throws &target, const free_throws &source);
int main()
{
free_throws one = {"Ifelsa Branch", 13, 14};
free_throws two = {"Andor Knott", 10, 16};
free_throws three = {"Minnie Max", 7, 9};
free_throws four = {"Whily Looper", 5, 9};
free_throws five = {"Long Long", 6, 14};
free_throws team = {"Throwgoods", 0, 0};
free_throws dup;
set_pc(one);
display(one);
accumulate(team, one);
display(team);
// use return value as argument
display(accumulate(team, two));
accumulate(accumulate(team, three), four);
display(team);
// use return value in assignment
dup = accumulate(team,five);
std::cout << "Displaying team:\n";
display(team);
std::cout << "Displaying dup after assignment:\n";
display(dup);
set_pc(four);
// ill-advised assignment
accumulate(dup,five) = four;
std::cout << "Displaying dup after ill-advised assignment:\n";
display(dup);
// std::cin.get();
system("pause");
return 0;
}
void display(const free_throws & ft)
{
using std::cout;
cout << "Name: " << ft.name << '\n';
cout << " Made: " << ft.made << '\t';
cout << "Attempts: " << ft.attempts << '\t';
cout << "Percent: " << ft.percent << '\n';
}
void set_pc(free_throws & ft)
{
if (ft.attempts != 0)
ft.percent = 100.0f *float(ft.made)/float(ft.attempts);
else
ft.percent = 0;
}
free_throws & accumulate(free_throws & target, const free_throws & source)
{
target.attempts += source.attempts;
target.made += source.made;
set_pc(target);
return target;
}
说明:
(a)在初始化多个结构对象时,如果指定的初始值比成员少,则余下的成员(这里的percent)将被设置为0.
(b)对于set_pc()函数而言
(c)对于display()函数而言
(d)对于accumulate()函数而言
(e)对于返回值是引用而言的说明如下,
具体意思就是:
(f)为何要返回引用??
(j)返回引用时需要注意的问题
错误的示例:返回临时变量
正确的方法1
正确的方法2
(h)为何将const用于引用返回类型?
第一点:
第二点:
5.将引用用于类对象
(1)通过使用引用,可以让函数将类string、ostream、istream、ofstream和ifstream等类的对象作为参数。
(2)eg的基本思想是:使用string类,创建一个函数,它将指定的字符串加入到另一个字符串的前面和后面。
#include<stdio.h>
#include<stdlib.h>
// strquote.cpp -- different designs
#include <iostream>
#include <string>
using namespace std;
string version1(const string & s1, const string & s2);
const string & version2(string & s1, const string & s2); // has side effect
const string & version3(string & s1, const string & s2); // bad design
int main()
{
string input;
string copy;
string result;
cout << "Enter a string: ";
getline(cin, input);
copy = input;
cout << "Your string as entered: " << input << endl;
result = version1(input, "***");
cout << "Your string enhanced: " << result << endl;
cout << "Your original string: " << input << endl;
result = version2(input, "###");
cout << "Your string enhanced: " << result << endl;
cout << "Your original string: " << input << endl;
cout << "Resetting original string.\n";
input = copy;
result = version3(input, "@@@");
cout << "Your string enhanced: " << result << endl;
cout << "Your original string: " << input << endl;
system("pause");
return 0;
}
string version1(const string & s1, const string & s2)
{
string temp;
temp = s2 + s1 + s2;
return temp;
}
const string & version2(string & s1, const string & s2) // has side effect
{
s1 = s2 + s1 + s2;
// safe to return reference passed to function
return s1;
}
const string & version3(string & s1, const string & s2) // bad design
{
string temp;
temp = s2 + s1 + s2;
// unsafe to return reference to local variable
return temp;
}
说明:
(a)将C语言风格的字符串用作string对象引用参数的说明
(b)对于第一个version1而言,
(c)对于第二个version2而言,
(d)对于第三个version3而言,不要对临时变量返回引用
6.对象、继承和引用
(1)ofstream对象可以使用ostream类的方法,这使得文件输入/输出的格式与控制台输入/输出相同;
(2)继承的特征1:
继承:使得能够将特性从一个类传递给另一个类的语言特性。
eg:
(3)继承的特征2:
(4)eg:
#include<stdio.h>
#include<stdlib.h>
//filefunc.cpp -- function with ostream & parameter
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
void file_it(ostream & os, double fo, const double fe[],int n);
const int LIMIT = 5;
int main()
{
ofstream fout;
const char * fn = "ep-data.txt";
fout.open(fn);
if (!fout.is_open())
{
cout << "Can't open " << fn << ". Bye.\n";
exit(EXIT_FAILURE);
}
double objective;
cout << "Enter the focal length of your "
"telescope objective in mm: ";
cin >> objective;
double eps[LIMIT];
cout << "Enter the focal lengths, in mm, of " << LIMIT
<< " eyepieces:\n";
for (int i = 0; i < LIMIT; i++)
{
cout << "Eyepiece #" << i + 1 << ": ";
cin >> eps[i];
}
file_it(fout, objective, eps, LIMIT);
file_it(cout, objective, eps, LIMIT);
cout << "Done\n";
system("pause");
return 0;
}
void file_it(ostream & os, double fo, const double fe[],int n)
{
// save initial formatting state
ios_base::fmtflags initial;
initial = os.setf(ios_base::fixed, ios_base::floatfield);
std::streamsize sz = os.precision(0);
os << "Focal length of objective: " << fo << " mm\n";
os.precision(1);
os.width(12);//可以不要
os << "f.l. eyepiece";
os.width(15);//可以不要
os << "magnification" << endl;
for (int i = 0; i < n; i++)
{
os.width(12);
os << fe[i];
os.width(15);
os << int (fo/fe[i] + 0.5) << endl;
}
// restore initial formatting state
os.setf(initial, ios_base::floatfield);
os.precision(sz);
}
说明:
(a)参数os(类型是ostream &)可以指向ostream对象(如cout),也可以指向ofstream对象(如fout)。
(b)使用ostream类中的格式化方法。
setf()能够设置各种格式化状态:
setf(ios_base::fixed)将对象置于使用定点表示;
setf(ios_base::showpoint)将对象置于显示小数点的模式,即小数部分为0;
precision()指定显示多少位小数(假设对象处于定点模式下);
width()设置下一次输出操作使用的字段宽度,这种设置只在显示下一个值时有效,然后就恢复到默认设置(默认为0);
所有这些设置都将一直保持不变,直到再次调用相应的方法重新设置它们(c)
7.何时使用引用参数??
三、默认参数
(1)默认参数指的是:当函数调用中省略了实参时,自动使用的一个值。
(2)如何设置默认值??
(3)对于带参数列表的函数而言
(4)对于实参而言
(5)默认参数的好处
(6)具体eg:
#include<stdio.h>
#include<stdlib.h>
// left.cpp -- string function with a default argument
#include <iostream>
const int ArSize = 80;
char * left(const char * str, int n = 1);
int main()
{
using namespace std;
char sample[ArSize];
cout << "Enter a string:\n";
cin.get(sample,ArSize);
char *ps = left(sample, 4);
cout << ps << endl;
delete [] ps; // free old string
ps = left(sample);
cout << ps << endl;
delete [] ps; // free new string
system("pause");
return 0;
}
// This function returns a pointer to a new string
// consisting of the first n characters in the str string.
char * left(const char * str, int n)
{
if(n < 0)
n = 0;
char * p = new char[n+1];
int i;
for (i = 0; i < n && str[i]; i++)
p[i] = str[i]; // copy characters
while (i <= n)
p[i++] = '\0'; // set rest of string to '\0'
return p;
}
说明:
(a)第一次用的是实参的参数,第二次使用的是默认参数,而默认参数在函数声明那里
(b)在函数char * left()中,很细节的考虑到了三个地方,并且用while循环来给新的字符串加结尾\0
(c)更进一步地,可以设置一种新字符串长度
(d)但是作为C语言程序员以及C++程序员,还可以做的更好,C程序员用strlen,C++程序员就会用比strlen更好的方法。
四、函数重载
(1)默认参数与函数多态(函数重载)的区别是:
默认参数让您能够使用不同数目的参数调用同一个函数;
**函数多态(函数重载)**让您能够使用多个同名的函数,即完成相同的工作,但是使用不同的参数列表。
(2)函数重载的关键是函数的参数列表——也称之为函数特征标(function signature)。C++允许定义名称相同的函数,条件是:它们的特征标不同,如果参数数目和或者参数类型不同,则特征标也不同。
(3)eg:
(4)有些不同的特征标是不能共存的:引用和类型本身视为同一个特征标
(5)
说明:
(a)dribble()函数有两个原型,一个用于const指针,另一个用于常规指针。
dribble()函数只与带非const参数的调用匹配;
drivel()函数可以与带const或者不带const参数的调用匹配;
(6)
(7)对于重载引用参数而言,类设计和STL会经常用到
1.函数重载的例子
(1)前面写了一个left()函数,它返回了一个指针,指向字符串的前n个字符。
在这里,再添加另一个left()函数,让其返回整数的前n位。
(2)编写的要点:
首先,先计算数字包含多少位。将数字除以10便可以去掉一位,因此,可以使用出发来计算数位。
其次,是要删除多少位
(3)最终,需要编写的函数的要求:由于考虑的多,所以最终的结果很完美
#include<stdio.h>
#include<stdlib.h>
// leftover.cpp -- overloading the left() function
#include <iostream>
unsigned long left(unsigned long num, unsigned ct);
char * left(const char * str, int n = 1);
int main()
{
using namespace std;
char * trip = "Hawaii!!"; // test value
unsigned long n = 12345678; // test value
int i;
char * temp;
for (i = 1; i < 10; i++)
{
cout << left(n, i) << endl;
temp = left(trip,i);
cout << temp << endl;
delete [] temp; // point to temporary storage
}
system("pause");
return 0;
}
// This function returns the first ct digits of the number num.
unsigned long left(unsigned long num, unsigned ct)
{
unsigned digits = 1;
unsigned long n = num;
if (ct == 0 || num == 0)
return 0; // return 0 if no digits
while (n /= 10)
digits++;//总共有多少位digits
if (digits > ct)
{
ct = digits - ct;
while (ct--)
num /= 10;
return num; // return left ct digits
}
else // if ct >= number of digits
return num; // return the whole number
}
// This function returns a pointer to a new string
// consisting of the first n characters in the str string.
char * left(const char * str, int n)
{
if(n < 0)
n = 0;
char * p = new char[n+1];
int i;
for (i = 0; i < n && str[i]; i++)
p[i] = str[i]; // copy characters
while (i <= n)
p[i++] = '\0'; // set rest of string to '\0'
return p;
}
2.何时使用函数重载
(1)
(2)
五、函数模板
1.函数模板的基本知识
(1)C++新增的一项特性——函数模板
使用泛型来定义函数,其中的泛型可用具体的类型(如int或double)替换。
通过将类型作为参数传递给模板,可使编译器生成该类型的函数。
由于模板允许以泛型(不是具体类型) 的方式编写程序,因此有时候也被称之为:通用编程。
(2)C++模板的到底是干啥的??
(3)举例一个函数模板的例子eg如下:
说明:
(a)
(b)使用模板的作用是:
(4)再举例一个函数模板的例子eg如下:
(5)函数模板在哪用?
(6)举个eg:
#include<stdio.h>
#include<stdlib.h>
// funtemp.cpp -- using a function template
#include <iostream>
// function template prototype
template <typename T> // or class T
void Swap(T &a, T &b);
int main()
{
using namespace std;
int i = 10;
int 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";
double x = 24.5;
double y = 81.7;
cout << "x, y = " << x << ", " << y << ".\n";
cout << "Using compiler-generated double swapper:\n";
Swap(x,y); // generates void Swap(double &, double &)
cout << "Now x, y = " << x << ", " << y << ".\n";
// cin.get();
system("pause");
return 0;
}
// function template definition
template <typename T> // or class T
void Swap(T &a, T &b)
{
T temp; // temp a variable of type T
temp = a;
a = b;
b = temp;
}
说明:
(a)用int替换了所有的T
(b)同理,用double替换了T
(3)使用模板的好处:使得生成的多个函数定义更简单、更可靠。
更常见的情况是,将模板放在头文件中,并在需要使用 模板的文件中包含头文件。
2.重载模板
(1)重载模板的特点:
由于并非所有的类型都使用相同的算法(函数模板的特点),可以像重载函数那样定义重载模板。
要求:被重载模板的函数特征标必须不同。
eg下面的例子:
特点:
#include<stdio.h>
#include<stdlib.h>
// twotemps.cpp -- using overloaded template functions
#include <iostream>
template <typename T> // original template
void Swap(T &a, T &b);
template <typename T> // new template
void Swap(T *a, T *b, int n);
void Show(int a[]);
const int Lim = 8;
int main()
{
using namespace std;
int i = 10, j = 20;
cout << "i, j = " << i << ", " << j << ".\n";
cout << "Using compiler-generated int swapper:\n";
Swap(i,j); // matches original template
cout << "Now i, j = " << i << ", " << j << ".\n";
int d1[Lim] = {0,7,0,4,1,7,7,6};
int d2[Lim] = {0,7,2,0,1,9,6,9};
cout << "Original arrays:\n";
Show(d1);
Show(d2);
Swap(d1,d2,Lim); // matches new template
cout << "Swapped arrays:\n";
Show(d1);
Show(d2);
// cin.get();
system("pause");
return 0;
}
template <typename T>
void Swap(T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
template <typename T>
void Swap(T a[], T b[], int n)
{
T temp;
for (int i = 0; i < n; i++)
{
temp = a[i];
a[i] = b[i];
b[i] = temp;
}
}
void Show(int a[])
{
using namespace std;
cout << a[0] << a[1] << "/";
cout << a[2] << a[3] << "/";
for (int i = 4; i < Lim; i++)
cout << a[i];
cout << endl;
}
3.模板的局限性
4.显示具体化
(1)显示具体化解决了上述所谓的模板局限性,
(2)重载模板的匹配顺序
eg:
(3)举一个显示具体化的eg,如下:
#include<stdio.h>
#include<stdlib.h>
// twoswap.cpp -- specialization overrides a template
#include <iostream>
template <typename T>
void Swap(T &a, T &b);
struct job
{
char name[40];
double salary;
int floor;
};
// explicit specialization
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);
system("pause");
return 0;
}
template <typename T>
void Swap(T &a, T &b) // general version
{
T temp;
temp = a;
a = b;
b = temp;
}
// swaps just the salary and floor fields of a job structure
template <> void Swap<job>(job &j1, job &j2) // specialization
{
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;
}
说明:
(a)cout中对精度的控制怎么写??
(b)Swap(i,j)匹配的是
Swap(sue,sidney)匹配的是
(c)这个模板具体化
(d)show()函数的形参中,定义了一个引用
5.实例化和具体化
(1)显示实例化和隐式实例化
(a)我们知道,编译器使用模板为特定类型生成函数定义时,得到的是模板实例(instantiation)。
隐式实例化
eg:
template
void Swap(T &a, T &b) // general version
{
T temp;
temp = a;
a = b;
b = temp;
}显式实例化
(b)显示具体化
(c)显示具体化和显示实例化的区别:
注意:
(2)
eg:对于其它的Swap()调用,编译器将根据函数调用时,实际使用的参数生成相应的版本。
6.编译器选择使用哪个函数版本
(1)重载解析及其过程
(2)理解重载解析的很重要的例子
eg:考虑只有一个函数参数的情况,如下面的调用:
首先编译器将寻找候选者, 即名称为may()的函数和函数模板(注意:只考虑特征标,不考虑返回类型)。然后寻找那些可以用一个参数调用的函数。
eg:
说明:把字符‘a’当作整型,
接下来,
结果是:
函数3,函数5>函数6>函数1>函数2
(3)完全匹配和最佳匹配
eg:
说明:
(a)情况1:不能完全匹配,编译器可能会提示的错误是:
(b)情况2:
(c)情况3:
eg1:
eg2:最具体的含义
用于找出最具体的模板的规则被称之为:函数模板的部分排序规则。
(4)部分排序规则的eg如下:
#include<stdio.h>
#include<stdlib.h>
// tempover.cpp --- template overloading
#include <iostream>
template <typename T> // template A
void ShowArray(T arr[], int n);
template <typename T> // template B
void ShowArray(T * arr[], int n);
struct debts
{
char name[50];
double amount;
};
int main()
{
using namespace std;
int things[6] = {13, 31, 103, 301, 310, 130};
//结构体数组
struct debts mr_E[3] =
{
{"Ima Wolfe", 2400.0},
{"Ura Foxe", 1300.0},
{"Iby Stout", 1800.0}
};
//指针数组
double * pd[3];
// set pointers to the amount members of the structures in mr_E
for (int i = 0; i < 3; i++)
pd[i] = &mr_E[i].amount;
cout << "Listing Mr. E's counts of things:\n";
// things is an array of int
ShowArray(things, 6); // uses template A
cout << "Listing Mr. E's debts:\n";
// pd is an array of pointers to double
ShowArray(pd, 3); // uses template B (more specialized)
// cin.get();
system("pause");
return 0;
}
template <typename T>
void ShowArray(T arr[], int n)
{
using namespace std;
cout << "template A\n";
for (int i = 0; i < n; i++)
cout << arr[i] << ' ';
cout << endl;
}
template <typename T>
void ShowArray(T * arr[], int n)
{
using namespace std;
cout << "template B\n";
for (int i = 0; i < n; i++)
cout << *arr[i] << ' ';
cout << endl;
}
说明:
(a) ShowArray(things, 6); // uses template A
(b)ShowArray(pd, 3); // uses template B (more specialized)
与模板A匹配的话,输出地址的原因是cout<<arr[i]<< ’ ’
与模板B匹配的话
(c)
(5)自己选择
#include<stdio.h>
#include<stdlib.h>
// choices.cpp -- choosing a template
#include <iostream>
template<class 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
// cin.get();
system("pause");
return 0;
}
说明:
(a)先看lesser(m, n)和lesser(x, y) 的情况
(b)再看lesser<>(m, n) 和 lesser< int >(x, y) 的情况
(6)多个参数的函数
7.函数模板的发展(了解即可,decltype关键字实在看得太少了)
(1)是什么类型??
(2)C++11的关键字decltype
(3)另一种函数声明语法(C++11后置返回类型)
六、总结