Skip to content

Latest commit

 

History

History
293 lines (236 loc) · 6.99 KB

07.md

File metadata and controls

293 lines (236 loc) · 6.99 KB

文章内容

一.CPlusPlus模板

二.函数模板

三.类模板

CPlusPlus模板

模板用来防止我们为不同的数据类型分别编写相同的函数或类。我们通常在需要为不同数据类型定义相同函数或类的大型程序中使用模板。模板是编写基础库和基础框架的利器,也是C++的精华所在。

为了理解它解决了什么问题,让我们先看看下面的程序。

#include <iostream>

using namespace std;

int sum( int x, int y)
{
	return x + y;
}
float sum( float x, float y)
{
	return x + y;
}
double sum( double x, double y)
{
	return x + y;
}

int main()
{
	cout << "Sum : " << sum(3, 5) << endl;
	cout << "Sum : " << sum(3.0, 5.2) << endl;
	cout << "Sum : " << sum(3.24234, 5.24144) << endl;
	return 0;
}
// OUTPUT:
/*
* Sum : 8
* Sum : 8.2
* Sum : 8.48378
*/

在本例中,我们定义了一个单独的函数来计算三组数字的和,每组数字都有不同的数据类型。为不同的数据类型一次又一次地定义相同的函数会出现大量冗余代码。

这就是我们需要模板的地方。在c++中有两种模板。

C++中有两种模板:

  • 函数模板
  • 类模板

函数模板

函数模板实现了即便是不同的数据类型也可定义单独的函数来执行相同的任务。让我们看看上面示例中的sum函数模板的语法。

T sum( T x, T y)
{
    return x + y;
}

将此函数模板与前面示例中的函数进行比较。明显注意到,这个函数模板与示例中的函数相同,区别在于,这里我们声明的参数类型为T,而不是int、float或double。

需要告诉编译器这是一个函数模板,因为它不能识别T(因为T不是关键字)。为此,我们需要在包含T之前包含以下代码,如下所示。

template <typename T>        
// 使用模板参数声明函数模板

那么,完整模板函数形式的sum函数如下

template <typename T>        
T sum( T x, T y)
{
    return x + y;
}

这将告诉编译器T是一种模板参数类型。 最初的代码可改为:

#include <iostream>

using namespace std;

template <typename T>
T sum( T x, T y)
{
    return x + y;
}

int main()
{
	cout << "Sum : " << sum(3, 5) << endl;
	cout << "Sum : " << sum(3.0, 5.2) << endl;
	cout << "Sum : " << sum(3.24234, 5.24144) << endl;
	return 0;
}
// OUTPUT:
/*
* Sum : 8
* Sum : 8.2
* Sum : 8.48378
*/

这里我们声明了一个函数模板,而不是为每种数据类型编写三个不同的函数。

T sum(tx, ty)这是函数模板的定义它和函数模板的定义是一样的。这告诉我们,两个参数都是T类型,返回值也是T类型。

sum(3,5)——因为参数(3和5)都是int类型,所以T将是int类型。

同样,对于sum(3.0, 5.2), T的类型变为float,该函数调用与第一个示例中的第二个函数相同。第三种情况也是如此。

现在我们知道了函数模板是如何工作的。

在声明模板参数时,我们还可以用class 关键字代替typename 关键字。

template < class T >        
// 声明模板参数

那么现在就存在一个问题,在上面的例子中,函数模板的两个参数都是相同类型的。因此我们声明T代表两者。但是,如果第一个参数与第二个参数的类型不同呢?

假设我们要用一个整数和一个浮点数相乘我们要为它定义一个函数。那么它的一个参数是int类型的,另一个是float类型的。在这种情况下,我们将为每个参数定义不同类型的函数模板,如下所示。

template	// 声明模板参数
T2 product( T1 x, T2 y)
{
    return x * y;
}

这里,我们声明了具有两种类型的模板参数T1和T2的函数模板,其中T1是它的第一个参数的数据类型,它是一个整数值,T2是第二个参数的数据类型,它是一个浮点值。因为整型和浮点数的乘积是浮点数,所以它的返回类型也是T2。

下面的示例演示了相同的情况。

#include <iostream>

using namespace std;

template < typename T1, typename T2 >
T2 product( T1 x, T2 y)
{
    return (T2)(x * y);
}

int main()
{
	cout << product(3, 4.7) << endl;
	cout << product(4, 5.6) << endl;
	return 0;
}
// OUTPUT:
/*
* 14.1
* 22.4
*/

类模板

我们可以像创建函数模板一样创建类模板。为了理解它,让我们举个例子。

考虑两个学生在一个班,我们想计算他们每个人在两个科目的总分数。假设两个主题中第一个学生的标记都是整数值,而第二个学生的标记都是浮点值。

示例如下:

#include <iostream>

using namespace std;

template <class T>
class Student
{
	T marks1;
	T marks2;
	public:
		Student(T m1, T m2): marks1(m1), marks2(m2){}
		T totalMarks();
		/*
		* 这是C语言式的声明方式不推荐
		* Student( T m1, T m2 )
		* {
		* 	 marks1 = m1;
		* 	 marks2 = m2;
		* }
		* T totalMarks()
		* {
		* 	 return marks1 + marks2;
		* }
		*/
};

template <class T>
T Student<T>::totalMarks()
{
	return marks1 + marks2;
}

int main()
{
	Student<int> s1 ( 45, 50 );
	Student<float> s2 ( 47.5, 56.4 );
	cout << "Total marks of student1 : " << s1.totalMarks() << endl;
	cout << "Total marks of student2 : " << s2.totalMarks() << endl;
	return 0;
}
// OUTPUT:
/*
* Total marks of student1 : 95
* Total marks of student2 : 103.9
*/

下面是稍微复杂一点的例子:

#include <iostream>
#include <cstdlib>
using namespace std;
struct Student {
  int id;       //学号
  float gpa;    //平均分
}; 
template <class T>
class Store {//类模板:实现对任意类型数据进行存取
private:
    T item; // item用于存放任意类型的数据
    bool haveValue;  // haveValue标记item是否已被存入内容
public:
    Store():haveValue(false){}
    T &getElem();   //提取数据函数
    void putElem(const T &x);  //存入数据函数
};

// template <class T>  
// Store<T>::Store(): haveValue(false) { }  
// 注:构造函数最好声明在内部
template <class T>
T &Store<T>::getElem() 
{
    //如试图提取未初始化的数据,则终止程序
    if (!haveValue) {   
        cout << "No item present!" << endl;
        exit(1);    //使程序完全退出,返回到操作系统。
    }
    return item;        // 返回item中存放的数据 
}
template <class T>
void Store<T>::putElem(const T &x) 
{
    // 将haveValue哨兵位,true表示item中已存入值了  
    haveValue = true;   
    item = x;           // 将x值存入item
}

int main() {
    Store<int> s1, s2;  
    s1.putElem(3);  
    s2.putElem(-7);
    cout << s1.getElem() << "  " << s2.getElem() << endl;

    Student g = { 1000, 23 };
    Store<Student> s3;
    s3.putElem(g); 
    cout << "The student id is " << s3.getElem().id << endl;

    Store<double> d;
    cout << "Retrieving object D... ";
    cout << d.getElem() << endl;
   //d未初始化,执行函数D.getElement()时导致程序终止
    return 0;
}
// OUTPUT:
/*
* 3  -7
* The student id is 1000
* Retrieving object D... No item present!
*/