模板函数和类在 C++ 中的作用类似于泛型在 C# 中的作用。它们允许您重用您的代码,而无需为您想要的每个变体编写函数或类。只要您提供给模板的类型具有模板使用的相关功能,一切都很好。如果没有,那么编译器会产生一个错误。这是因为编译器会为您使用的每个专门化生成一个唯一的类。因为编译器从程序的模板中构建类和函数,所以模板函数和类必须放入头文件中并完全内联定义。这样,编译器可以为所有使用它们的源代码文件解析它们。
最终,模板会变得非常复杂。C++ 标准库展示了高级模板的能力和复杂性。尽管如此,您不需要模板的高级知识来有效地使用它们。了解 C++ 模板的基础将有助于您释放大量的功能和力量。
模板函数是至少接受一个模板参数的独立函数。它接受一个参数的事实使得它在用一个具体的参数调用之前是不完整的,从而导致模板成为一个完全定义的函数。这里有一个接受两个参数的模板函数。
示例:模板示例\PeekLastItem.h
#pragma once
template<class T, class U>
U PeekLastItem(T& collection)
{
return *collection.rbegin();
}
任何模板(函数或类)的创建都是从关键字template
开始,然后是箭头括号内的参数,如前一个示例中的class T
和class U
所示。在T
和U
之前使用class
一词并不意味着那些论点一定是阶级。把class
想象成一个普通的词,用来表达非特定类型的意思。您可以使用混凝土类型的模板,也可以使用非特定类类型和混凝土类型的混合模板,如template<class T, int>
。使用T
作为第一个参数的名称,使用U
作为第二个参数的名称是一种常见的做法,而不是一种要求。几乎可以使用任何东西作为模板参数名。
前面的函数引用了类型为 T 的项目。它假设 T 将有一个名为rbegin
的成员函数,该函数可以在没有参数的情况下调用,并将返回一个指针类型,当被取消引用时,该指针类型将成为类型为 U 的对象。这个特殊的函数主要设计用于 C++ 标准库的许多集合类,尽管任何满足该函数对类型 T 的假设的类都可以与这个模板函数一起使用。采用任何类型,向其添加必要的功能,从而使其适合与模板一起使用的能力是模板的主要吸引力。
模板类类似于模板函数,只是它们是类而不是简单的单机函数。我们来看一个例子。
示例:模板示例\简单数学
#pragma once
template<class T>
class SimpleMath
{
public:
SimpleMath(void) { }
~SimpleMath(void) { }
T Add(T a, T b)
{
return a + b;
}
T Subtract(T a, T b)
{
return a - b;
}
T Multiply(T a, T b)
{
return a * b;
}
T Divide(T a, T b)
{
return a / b;
}
};
顾名思义,这个类不仅仅是一个演示。只有一个类型参数。查看类定义,我们可以推导出这种情况下对T
的要求是它有以下操作符,所有操作符对T
的两个实例进行操作,并返回一个T:
的实例
+
-
*
/
虽然这些在逻辑上属于数字,但是您可以为任何类或数据类型定义这些运算符,然后实例化该模板类的实例,该实例是为您的自定义类(例如,矩阵类)专门设计的。
最后一点,如果您要在类定义之外定义成员函数,但是仍然在同一个头文件中,那么您当然需要在声明中使用 inline 关键字;定义如下:SimpleMath<T>::SimpleMath(void) { }
。
这是该示例的最后一个文件,显示了前面每个模板的简单用法。
示例:模板样本\模板样本. cpp
#include <iostream>
#include <ostream>
#include <vector>
#include "SimpleMath.h"
#include "PeekLastItem.h"
#include "../pchar.h"
using namespace std;
int _pmain(int /*argc*/, _pchar* /*argv*/[])
{
SimpleMath<float> smf;
wcout << "1.1F + 2.02F = " << smf.Add(1.1F, 2.02F) << "F." <<
endl;
vector<const wchar_t*> strs;
strs.push_back(L"Hello");
strs.push_back(L"World");
wcout << L"Last word was '" <<
PeekLastItem<std::vector<const wchar_t*>,const wchar_t*>(strs) <<
L"'." << endl;
return 0;
}