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. 转发 python中file和open有什么区别

    python中file和open有什么区别?2008-04-15 11:30地痞小流氓 | 分类:python | 浏览3426次python中file和open有什么区别?都是打开文件,说的越详细越 ...

  2. OBIEE 11g:Error:nQSError 36010 Server version 318 cannot read the newer version of the repository

    biee11g升级到最新版以后,发现了一些bug,需要回退到原来的版本,卸载掉升级包以后,启动BI服务,会报上述错误.这是因为资料库文件已经升级为了最新版本.这时候我们需要将资料库文件进行降版本操作. ...

  3. [SQL_Server_Question]Msg 1105无法为数据库 'tempdb' 中的对象分配空间,因为 'PRIMARY' 文件组已满

    错误消息: Msg 1105, Level 17, State 2, Line 266Could not allocate space for object 'dbo.Large Object Sto ...

  4. Mysql 数据分组取某字段值所有最大的记录行

    需求: 表中同一个uid(用户)拥有多条游戏等级记录,现需要取所有用户最高等级(level)的那一条数据,且时间(time)越早排越前.这是典型的排名表 +------+-------+------- ...

  5. java转义字符

    JAVA中转义字符: 1.八进制转义序列:\ + 1到3位5数字:范围'\000'~'\377'       \0:空字符 2.Unicode转义字符:\u + 四个十六进制数字:0~65535    ...

  6. StackExchange.Redis的使用

    StackExchange.Redis介绍 有需要了解的和基础的使用可以参考:http://www.cnblogs.com/bnbqian/p/4962855.html StackExchange.R ...

  7. c++类中的静态成员

    静态成员和非静态成员的区别: 类静态成员用static修饰,类的静态成员属于类本身,而不属于类的某个具体对象,静态成员被类的所有对象共享,因此某个对象对静态成员(数据成员)的修改对其对象是可见的.而类 ...

  8. 网络笔记01-3 socket 实现百度页面的两种方式

    scoket 实现百度页面的两种方式: 1.利用系统自带    //1.创建URL NSURL *url=[NSURL URLWithString:@"http://m.baidu.com& ...

  9. c++ break while

    #include <iostream> #include <vector> #include <pthread.h> #include "destory_ ...

  10. oracle——分析函数——排序值分析函数

    一.问题描述 查询列表时,我们有时需要对查询结果依据某个字段进行排名. 如果每条记录在排序字段上都不相同,我们可以将原查询作为一个视图,查询其rownum,便可以实现简单排序,例如: select r ...