6.3 类模板和模板类

所谓类模板,实际上是建立一个通用类,其数据成员、成员函数的返回值类型和形参类型不具体指定,用一个虚拟的类型来代表。使用类模板定义对象时,系统会实参的类型来取代类模板中虚拟类型从而实现了不同类的功能。

定义一个类模板与定义函数模板的格式类似,必须以关键字template开始,后面是尖括号括起来的模板参数,然后是类名,其格式如下:

template <typename 类型参数>
class 类名{
       类成员声明
};

或者

template <class 类型参数>
class 类名{
       类成员声明
};

(1)template:是一个声明模板的关键字,它表明声明一个模板
(2)类型参数:通常用C++标识符表示,如T、Type等,实际上是一个虚拟的类型名,现在未指定它是哪一种具体的类型,但使用类模板时,必须将类型参数实例化。

(3)typename和class的作用相同,都是表示其后面的参数是一个虚拟的类名(即类型参数).

在类声明中,欲采用通用数据类型的数据成员、成员函数的参数或返回类型前面需要加上类型参数。

如建立一个用来实现求两个数最大值的类模板

template<typename T>    //模板声明,其中T为类型参数
class Compare{
public:
Compare(T i,T j)
{
x = i;
y = j;
}
T max()
{
return (x>y)?x:y;
}
private:
T x,y;
};

用类模板定义对象时,采用以下形式:

类模板名<实际类型名>对象名[(实参表列)];

因此,使用上面求最大值的类型模板的主函数可写成:

 int main()
{
Compare<int>com1(,);
Compare<double>com2(12.34,56.78);
Compare<char>com3('a','x');
cout<<"其中的最大值是:"<<com1.max()<<endl;
cout<<"其中的最大值是:"<<com2.max()<<endl;
cout<<"其中的最大值是:"<<com3.max()<<endl;
return ;
}

//例6.6 类模板compare的使用举例

#include<iostream.h>
template<typename T> //模板声明,其中T为类型参数
class Compare{
public:
Compare(T i,T j)
{
x = i;
y = j;
}
T max()
{
return (x>y)?x:y;
}
private:
T x,y;
};
int main()
{
Compare<int>com1(,); //用类模板定义对象com1,此时T被int替代
Compare<double>com2(12.34,56.78); //用类模板定义对象com2,此时T被double替代
Compare<char>com3('a','x'); //用类模板定义对象com3,此时T被char替代
cout<<"其中的最大值是:"<<com1.max()<<endl;
cout<<"其中的最大值是:"<<com2.max()<<endl;
cout<<"其中的最大值是:"<<com3.max()<<endl;
return ;
}
/*
程序运行结果是:
其中的最大值是:7
其中的最大值是:56.78
其中的最大值是:x
*/

在以上例子中,成员函数(其中含有类型参数)是定义类体内的。但是,类模板中的成员函数,也可以在类模板外定义。此时,若成员函数中有参数类型存在,则C++有一些特殊的规定:

(1)需要在成员函数定义之前进行模板声明;
(2)在成员函数名前缀上"类名<类型参数>::";

在类模板外定义成员函数的一般形式如下:

temlate<typename 类型参数>
函数类型 类名<类型参数>::成员函数名(形参表)

函数体;
} 如上题中成员函数max在类模板外定义时,应该写成:
template<typename T>
T Compare<T>::max()
{
return (x>y)?x:y;
}

//例6.7 在类模板外定义成员函数函数举例。

#include<iostream.h>
template<typename T> //模板声明,其中T为类型参数
class Compare{
public:
Compare(T i,T j)
{
x = i;
y = j;
}
T max();
private:
T x,y;
};
template<class T>
T Compare<T>::max()
{
return (x>y)?x:y;
}
int main()
{
Compare<int>com1(,); //用类模板定义对象com1,此时T被int替代
Compare<double>com2(12.34,56.78); //用类模板定义对象com2,此时T被double替代
Compare<char>com3('a','x'); //用类模板定义对象com3,此时T被char替代
cout<<"其中的最大值是:"<<com1.max()<<endl;
cout<<"其中的最大值是:"<<com2.max()<<endl;
cout<<"其中的最大值是:"<<com3.max()<<endl;
return ;
}
/*
程序运行结果是:
其中的最大值是:7
其中的最大值是:56.78
其中的最大值是:x 此例中,类模板Compare经实例化后生成了3个类型分别为int、double、char的模板类,这3个模板类
经实例化后又生成了3个对象com1、com2、com3。类模板代表了一类类,模板类表示某一具体的类。关系如下: 类模板
Compare<T>
实例化成模板类:Compare<int> Compare<double> Compare<char>
实例化模板类对象:com1 com2 com3
*/

//例6.8 类模板Stack的使用举例。

#include<iostream.h>
const int size=;
template<class T> //模板声明,其中T为类型参数
class Stack{ //类模板为Stack
public:
void init()
{
tos=;
}
void push(T ob); //声明成员函数push的原型,函数参数类型为T类型
T pop(); //声明成员函数pop的原型,其返回值类型为T类型
private:
T stack[size]; //数组类型为T,即是自可取任意类型
int tos;
};
template<class T> //模板声明
void Stack<T>::push(T ob) //在类模板体外定义成员函数push
{
if(tos==size)
{
cout<<"Stack is full"<<endl;
return;
}
stack[tos]=ob;
tos++;
}
template<typename T> //模板声明
T Stack<T>::pop() //在类模板体外定义成员函数push
{
if(tos==)
{
cout<<"Stack is empty"<<endl;
return ;
}
tos--;
return stack[tos];
}
int main()
{
//定义字符堆栈
Stack<char> s1; //用类模板定义对象s,此时T被char取代
s1.init();
s1.push('a');
s1.push('b');
s1.push('c');
for(int i=;i<;i++){cout<<"pop s1:"<<s1.pop()<<endl;} //定义整型堆栈
Stack<int> s2; //用类模板定义对象s,此时T被int取代
s2.init();
s2.push();
s2.push();
s2.push();
for(int i=;i<;i++){cout<<"pop s2:"<<s2.pop()<<endl;} return ;
} /*
程序运行结果是:
pop s1:c
pop s1:b
pop s1:a
pop s2:5
pop s2:3
pop s2:1 说明:
(1)在每一个类模板定义之前,都需要在前面加上模板声明,如
template<typename T>

tempplate<class T> 并且,类模板在使用时,必须在模板类名字后面缀上<类型参数> ,如
Stack<T> (2)如同模板函数一样,模板类也可以有多个类型参数。
*/

//例6.9 有两个类型参数的类模板举例

#include<iostream.h>
template<class QQ,class T> //声明模板,具有T1,T2两个类型参数
class Myclass{ //定义模板类Myclass
public:
Myclass(QQ a,T b);
void show();
private:
QQ x;
T y;
};
template<typename QQ,typename T>
Myclass<QQ,T>::Myclass(QQ a,T b)
{
x = a;
y = b;
}
template<class QQ,class T>
void Myclass<QQ,T>::show()
{
cout<<"x="<<x<<","<<"y="<<y<<endl;
}
int main()
{
Myclass <int,double>m1(,0.15); //用类模板定义对象m1,此时T1,T2分别被int、double取代
Myclass <int,char*>m2(,"This a test."); //用类模板定义对象m2,此时T1,T2分别被int,char*取代 m1.show();
m2.show(); return ;
}
/*
程序运行结果是:
x=12,y=0.15
x=12,y=This a test.
*/

C++:类模板与模板类的更多相关文章

  1. C++中模板类使用友元模板函数

    在类模板中可以出现三种友元声明:(1)普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数.(2)类模板或函数模板的友元声明,授予对友元所有实例的访问权.(3)只授予对类模板或函数模板的特定 ...

  2. CI 模板解析器类

    模板解析器类可以解析你的视图文件中的伪变量.它可以解析简单的变量或者以变量作为标签的结构.如果你以前没有用过模板引擎,那么伪变量如下所示: <html><head><ti ...

  3. 读书笔记 effective c++ Item 43 了解如何访问模板化基类中的名字

    1. 问题的引入——派生类不会发现模板基类中的名字 假设我们需要写一个应用,使用它可以为不同的公司发送消息.消息可以以加密或者明文(未加密)的方式被发送.如果在编译阶段我们有足够的信息来确定哪个信息会 ...

  4. C++ 类模板与模板类详解

    在C++的Template中很多地方都用到了typename与class这两个关键字,有时候这两者可以替换,那么这两个关键字是否完全一样呢? 事实上class用于定义类,在模板引入c++后,最初定义模 ...

  5. C++类模板和模板类

    C++ 中有一个重要特性,那就是模板类型.类似于Objective-C中的泛型.C++通过类模板来实现泛型支持. 1 基础的类模板 类模板,可以定义相同的操作,拥有不同数据类型的成员属性. 通常使用t ...

  6. 如何导出标准模板库(STL)类的实例化和包含STL类对象数据成员的类

    本文翻译自 https://support.microsoft.com/zh-cn/help/168958/how-to-export-an-instantiation-of-a-standard-t ...

  7. 《C++ Primer Plus》第16章 string类和标准模板库 学习笔记

    C++提供了一组功能强大的库,这些库提供了很多常见编程问题的解决方案以及简化其他问题的工具string类为将字符串作为对象来处理提供了一种方便的方法.string类提供了自动内存管理动能以及众多处理字 ...

  8. C++ 类模板三(类模版中的static关键字)

    //类模版中的static关键字 #include<iostream> using namespace std; /* 类模板本质上是c++编译器根据类型参数创建了不同的类, c++编译器 ...

  9. C++ 类模板一(类模板的定义)

    //类模版语法 #include<iostream> using namespace std; /* 类模板和函数模板深入理解 1.编译器并不是把函数模板处理成能处理任何类型的函数 2.编 ...

随机推荐

  1. ODBC连接发生错误:未发现数据源名称并且未指定默认驱动程序

    程序在使用ODBC方式连接数据库时发生错误: ERROR [IM002] [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序. 什么原因造成的呢? 本人使用&l ...

  2. CORS(跨域资源共享)简介

    前言:像CORS对于现代前端这么重要的技术在国内基本上居然很少有人使用和提及,在百度或者Google上搜索CORS,搜到的中文文章基本都是另外一种卫星定位技术CORS的介绍,让我等前端同学情何以堪(对 ...

  3. 如何成为Python高手(转载)

    本文是从 How to become a proficient Python programmer 这篇文章翻译而来. 这篇文章主要是对我收集的一些文章的摘要.因为已经有很多比我有才华的人写出了大量关 ...

  4. jQuery对复选框(checkbox)的全选,全不选,反选等的操作

    效果截图: HTML代码: <body><ul id="list"> <li><label><input type=" ...

  5. &lt;iframe&gt;标签的一些说明

    <iframe>标签里的marginwidth/marginheight属性定义的是框架内部的margin(框架和其父元素之间的margin可以用style="margin:.. ...

  6. 基于spring-boot的web应用,ckeditor上传文件图片文件

    说来惭愧,这个应用调试,折腾了我一整天,google了很多帖子,才算整明白,今天在这里做个记录和分享吧,也作为自己后续的参考! 第一步,ckeditor(本博文论及的ckeditor版本4.5.6)的 ...

  7. 【Linux笔记】Linux目录结构

    [Linux笔记]Linux目录结构   本文内容整理自网络,以作参考. /:根目录,位于linux文件系统目录结构的顶层,一般根目录下只存放目录,不要存放文件,/etc./bin./dev./lib ...

  8. Jquery的$命名冲突

    在Jquery中,$是JQuery的别名,所有使用$的地方也都可以使用JQuery来替换,如$('#msg')等同于JQuery('#msg')的写法.然而,当我们引入多个js库后,在另外一个js库中 ...

  9. Codeforces 14D

    #include<iostream> #include<cstdio> #include<cstring> using namespace std; const i ...

  10. 简单的实现QQ通信功能(二)

    第二部分:功能需求以及大体思路 一:功能需求: 1. 角色:登录用户. 2. 登录: (1)检查用户名和密码是否正确,正确登录成功,否则提醒用户名或密码错误. (2)登录时可以选择登录状态,送入数据库 ...