在C ++中,两种不同的功能可以有,如果他们的参数不同,相同的名称; 或者是因为它们具有不同数目的参数,或者是因为它们的任何参数的是不同的类型。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// overloading functions
#include
using namespace std;
int operate (int a, int b)
{
return (a*b);
}
double operate (double a, double b)
{
return (a/b);
}
int main ()
{
int x=5,y=2;
double n=5.0,m=2.0;
cout << operate (x,y) << '\n';
cout << operate (n,m) << '\n';
return 0;
} |
10
2.5 |
|
在这个例子中,有两个功能调用
operate
,但它们中的一个具有类型的两个参数
int
,而其他有类型的它们
double
。编译器知道哪一个在每种情况下通过检查作为参数传递的类型时调用该函数调用。如果它被称为具有两个
int
参数,它调用到具有两个功能
int
的参数,并且如果它被称为具有两个
double
s时,调用所述一个具有两个
double
第
在这个例子中,这两种功能都相当不同的行为,该
int
版本相乘它的参数,而
double
版本将其划分。这通常不是一个好主意。具有相同名称的两个函数通常预期具有-at least-一个类似的行为,但此实施例证明是完全有可能对他们不要。两个重载函数(即具有相同名称的两个函数)具有完全不同的定义; 他们是,对于所有的目的,不同的功能,只发生在具有相同的名称。
注意,一个功能不仅可以通过其返回类型被重载。至少它的一个参数必须有不同的类型。
功能模板
重载函数可以具有相同的定义。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// overloaded functions
#include
using namespace std;
int sum (int a, int b)
{
return a+b;
}
double sum (double a, double b)
{
return a+b;
}
int main ()
{
cout << sum (10,20) << '\n';
cout << sum (1.0,1.5) << '\n';
return 0;
} |
三十
2.5 |
|
这里,
sum
是重载用不同的参数的类型,但具有完全相同的身体。
该函数
sum
可以被超载了很多类型,并且它可以使感为他们都具有相同的机构。对于这样的情况下,C ++有定义与泛型类型,称为功能的能力
函数模板。定义一个函数模板遵循相同的语法作为一个普通的功能,但它是由前面
template
的关键字等一系列括在尖括号<>模板参数:
template function-declaration
模板参数是一系列由逗号分隔的参数。这些参数可以通过指定的通用模板的类型
class
或
typename
关键字后跟一个标识符。该标识符然后可以在函数声明中使用,就好像它是一个普通的类型。例如,通用的
sum
函数可以定义为:
1
2
3
4
5
|
template
SomeType sum (SomeType a, SomeType b)
{
return a+b;
} |
|
它使没有差别是否泛型类型与关键字指定
class
或关键字
typename
在模板参数列表(他们是在模板声明100%的同义词)。
在上面的代码中,声明
SomeType
(括在尖括号中的模板参数中的泛型类型)允许
SomeType
将函数定义的任何地方使用,就像任何其他类型的; 它可以被用作参数的类型,如返回类型,或者声明该类型的新变量。在所有的情况下,它表示将模板上被实例化的时刻来确定一个通用的类型。
实例化一个模板是应用模板来创建使用特定类型或值其模板参数的函数。这是通过调用完成
函数模板,具有相同的语法与调用一个普通的功能,但指定尖括号括起来的模板参数:
name (function-arguments)
例如,
sum
上面定义的函数模板可以调用:
该功能
sum
只是函数模板的可能实例之一
sum
。在这种情况下,通过使用
int
如在呼叫模板参数时,编译器自动实例化的一个版本
sum
,其中在每次出现时
SomeType
被替换
int
,因为如果它被定义为:
1
2
3
4
|
int sum (int a, int b)
{
return a+b;
} |
|
让我们看一个实际的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// function template
#include
using namespace std;
template
T sum (T a, T b)
{
T result;
result = a + b;
return result;
}
int main () {
int i=5, j=6, k;
double f=2.0, g=0.5, h;
k=sum(i,j);
h=sum(f,g);
cout << k << '\n';
cout << h << '\n';
return 0;
} |
11
2.5 |
|
在这种情况下,我们使用
T
作为模板的参数名,代替
SomeType
。它没有什么区别,而
T
实际上是泛型类型很常见的模板参数的名字。
在上面的例子中,我们使用了功能模板
sum
的两倍。第一次用类型的参数
int
,而第二个类型的参数
double
。编译器实例化,然后叫每次函数的相应版本。
还要注意如何
T
也被用来声明那(通用)的局部变量中键入
sum
:
因此,结果将是相同的类型的参数的变量
a
和
b
,并作为由该函数返回的类型。
在一般类型这种特定情况下
T
被用作一个参数
sum
,编译器甚至能无需尖括号内明确指定它自动推断的数据类型。因此,而不是显式指定与模板参数:
1
2
|
k = sum (i,j);
h = sum (f,g); |
|
这是可能的,而不是简单地写:
1
2
|
k = sum (i,j);
h = sum (f,g); |
|
没有尖括号括起来的类型。当然,对于,类型应是毫不含糊的。如果
sum
被调用,不同类型的参数,编译器可能不能够推断出的类型
T
自动。
模板是一个强大和灵活的功能。它们可以有多个模板的参数,并且函数仍然可以使用常规的非模板化的类型。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// function templates
#include
using namespace std;
template
bool are_equal (T a, U b)
{
return (a==b);
}
int main ()
{
if (are_equal(10,10.0))
cout << "x and y are equal\n";
else
cout << "x and y are not equal\n";
return 0;
} |
x和y是等于 |
|
注意,这个例子使用自动模板参数推导在调用
are_equal
:
相当于:
没有歧义可能的,因为数字文字是一种特殊类型的总是:除非带有后缀另有规定外,整数文字总会产生类型的值
int
,和浮点文字总会产生类型的值
double
。因此
10
一直键入
int
,并
10.0
一直类型
double
。
非类型模板参数
模板参数不仅可以包括通过引入类型
class
或
typename
,但也可包括一个特定类型的表达式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// template arguments
#include
using namespace std;
template
T fixed_multiply (T val)
{
return val * N;
}
int main() {
std::cout << fixed_multiply(10) << '\n';
std::cout << fixed_multiply(10) << '\n';
} |
20
三十 |
|
在的第二个参数
fixed_multiply
函数模板类型
int
。它只是看起来像一个普通的函数参数,实际上可以用宛若一体。
但存在一个主要区别:是在编译时确定的模板参数值来生成功能的不同实例
fixed_multiply
,因此该参数的值在运行时不会传递:两个调用
fixed_multiply
在
main
本质上调用的两个版本功能:一个总是由两个相乘,和一个总是由三个相乘。
对于同样的原因,第二个模板参数必须是一个常量表达式(它不能被传递一个变量)。