c++教程(九:Overloads and templates)

    xiaoxiao2025-08-29  39

    ————————————————————————

    该系列教程为翻译c++官方教程,点击参考英文原版,水平有限,翻译不通之处敬请谅解!

    ————————————————————————

    Overloaded functions

    在c++中,两个函数如果参数不同也可以有相同的函数名。虽然他们的参数个数、参数类型都可能不相同。例如:

    // overloading functions #include <iostream> 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; }

    在这个例子中,两个函数都被称为operate,但是一个包含int型的两个参数,另外一个包含double型。编译器根据他们的类型就可以知道什么时候该调用哪一个函数。如果输入参数是int型的,那么就调用int参数对应的函数,同样是double的就调用double的函数。

    在这个例子中,两个函数的功能完全不一样。Int型函数执行的是相乘的操作,二double型只执行的是相除的操作,一般情况下这样做并不好。相同的函数名至少应该拥有相似的功能才对。但是你这个例子正好相反。两个重载函数(两个函数名相同)有完全不同的定义。他们就是拥有相同函数名功能却不同的函数。

    注意一个函数只靠返回参数类型是不可以实现重载的。至少他们的参数类型是不一样的。

    函数模板

    重载函数可以有相同的定义,比如:

    // overloaded functions #include <iostream> 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; }

    在这个例子中,sum就被重载有不同参数类型,但是函数的主体内容是一样的 函数sum可以被许多不同类型所重载,并且拥有相同的函数主体。像这样,c++可以根据函数的的类型辨别具体是哪个函数,这也被称为函数的模板。定义一个函数的模板,除了需要知道函数的类型的关键字以外,还需要使用一对尖括号括起来<>;

    template < template-parameters > function-declaration 模板参数是用一系列逗号隔开的参数,这些参数可以使用通用template类型来定义是一个class或者 typename关键字标识符。这些标识符就可以用于函数声明为某一个类型。例如通用的sum函数此时可以写成:

    template <class SomeType> SomeType sum (SomeType a, SomeType b) { return a+b; }

    通用类型是使用关键字class还是typename在参数列表中没有影响(他们在模板声明中100%是个同义词)

    上述代码声明了一个SomeType (一个通用类型的声明),这使得SomeType可以用于任何函数声明,像其他类型一样。它可以当做输入参数的类型,输出类型,或者声明参数的类型,在所有情况下,它代表的一种通用的类型将取决于当下的模板实例化。

    实例化一个模板就是应用模板来使用特定的类型或值的模板参数创建一个函数。这是做法被称为调用函数模板,以相同的语法来调用一个正则函数,但指定的模板参数应该在封闭的括号内:

    name < template-arguments> (function-arguments) 函数sum< int>只是函数sum模板的一个可能的实例化。这种情况下,使用int作为模板调用参数,这样的话编译器就会将int赋值于任何SomeType所在的位置并替换掉,就好比定义了:

    int sum (int a, int b) { return a+b; }

    让我们看一个实际的例子:

    // function template #include <iostream> using namespace std; template <class T> 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<int>(i,j); h=sum<double>(f,g); cout << k << '\n'; cout << h << '\n'; return 0; }

    在这个例子中,我们使用T作为模板参数的名字,代替SomeType,这是没有影响的,T相对来说是一种更为广泛的使用参数。

    上面的这个例子,我们使用sum函数两次,第一次是以int型使用,第二次是以double函数使用,编译器通过实例化来把他们实现出来。要注意的是T是如何实例化一个局部变量的: T result;

    因此,结果将是一个与参数a和b相同类型的变量,并作为函数返回的类型。 在这种特定的情况下,通用类型的T作为函数sum的返回参数,编译器甚至能够自动推断出数据类型,而无需显式指定它在角括号内。因此,不需要显式指定模板参数:

    k = sum<int> (i,j); h = sum<double> (f,g

    ); 甚至可以更简单的写为:

    k = sum(i,j); h = sum(f,g);

    不需要再尖括号中定义类型。一般来说那样的话,对于该类型,类型应明确。如果sum被不同类型的参数所调用,编译器可能就无法确定T的类型。

    模板是一种强大有效的方法,它可以有更多的模板类型,函数也可以使用更多不同类型方法。例如:

    // function templates #include <iostream> using namespace std; template <class T, class U> 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; }

    注意在这个函数中,我们使用了自动识别类型方法来调用函数are_equal:

    are_equal(10,10.0)

    它等价于:

    are_equal<int,double>(10,10.0)

    这里没有任何歧义,因为一个数值总有一种特定类型,除非另有规定,整数总是认为是int类型,浮点数总是认为是double型。因此,10为int型,10为double型。

    没有类型的模板参数

    模板参数不仅可以包含前面介绍的class和typename,也可以是其他某个具体的类型:

    // template arguments #include <iostream> using namespace std; template <class T, int N> T fixed_multiply (T val) { return val * N; } int main() { std::cout << fixed_multiply<int,2>(10) << '\n'; std::cout << fixed_multiply<int,3>(10) << '\n'; }

    函数fixed_multiply的第二个参数被认为是int类型,就像一个已经得定义好的参数,那么这个函数可以被认为是只有一个参数。

    但存在一个主要的区别:模板参数的值是在编译时生成不同的实例化函数由fixed_multiply来确定,从而参数的值绝在运行时不能被调用:两个fixed_multiply函数主要是调用的函数的两个版本:一个总是乘以二,一总是乘以三。同样,第二个模板的参数需要是一个常量表达式(它不能传递一个变量)。

    转载请注明原文地址: https://ju.6miu.com/read-1302117.html
    最新回复(0)