C++:类模板与模板类
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++:类模板与模板类的更多相关文章
- C++中模板类使用友元模板函数
在类模板中可以出现三种友元声明:(1)普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数.(2)类模板或函数模板的友元声明,授予对友元所有实例的访问权.(3)只授予对类模板或函数模板的特定 ...
- CI 模板解析器类
模板解析器类可以解析你的视图文件中的伪变量.它可以解析简单的变量或者以变量作为标签的结构.如果你以前没有用过模板引擎,那么伪变量如下所示: <html><head><ti ...
- 读书笔记 effective c++ Item 43 了解如何访问模板化基类中的名字
1. 问题的引入——派生类不会发现模板基类中的名字 假设我们需要写一个应用,使用它可以为不同的公司发送消息.消息可以以加密或者明文(未加密)的方式被发送.如果在编译阶段我们有足够的信息来确定哪个信息会 ...
- C++ 类模板与模板类详解
在C++的Template中很多地方都用到了typename与class这两个关键字,有时候这两者可以替换,那么这两个关键字是否完全一样呢? 事实上class用于定义类,在模板引入c++后,最初定义模 ...
- C++类模板和模板类
C++ 中有一个重要特性,那就是模板类型.类似于Objective-C中的泛型.C++通过类模板来实现泛型支持. 1 基础的类模板 类模板,可以定义相同的操作,拥有不同数据类型的成员属性. 通常使用t ...
- 如何导出标准模板库(STL)类的实例化和包含STL类对象数据成员的类
本文翻译自 https://support.microsoft.com/zh-cn/help/168958/how-to-export-an-instantiation-of-a-standard-t ...
- 《C++ Primer Plus》第16章 string类和标准模板库 学习笔记
C++提供了一组功能强大的库,这些库提供了很多常见编程问题的解决方案以及简化其他问题的工具string类为将字符串作为对象来处理提供了一种方便的方法.string类提供了自动内存管理动能以及众多处理字 ...
- C++ 类模板三(类模版中的static关键字)
//类模版中的static关键字 #include<iostream> using namespace std; /* 类模板本质上是c++编译器根据类型参数创建了不同的类, c++编译器 ...
- C++ 类模板一(类模板的定义)
//类模版语法 #include<iostream> using namespace std; /* 类模板和函数模板深入理解 1.编译器并不是把函数模板处理成能处理任何类型的函数 2.编 ...
随机推荐
- DATE,DATETIME,DATETIME2等日期时间数据类型
日期范围广 0001-01-01 到 9999-12-31.时间范围广 00:00:00 到 23:59:59.9999999. -----------------DATE --只存储日期 selec ...
- static方法不能直接访问类内的非static变量和不能调用this,super语句分析
大家都知道在static方法中,不能访问类内非static成员变量和方法.可是原因是什么呢? 这首先要从static方法的特性说起.static方法,即类的静态成员经常被称为"成员变量&qu ...
- python之range(), xrange()
可以这样理解: range()立即执行,返回结果 xrange()延迟执行,需要时再返回结果.
- 加载驱动模块时Device or resource busy的解决方法
加载驱动模块时Device or resource busy的解决方法 加载驱动模块时Device or resource busy的解决方法 insmod或modprobe驱动模块时Device o ...
- matlab实现复合梯形法则
复合梯形法则: function int_f = CompoundEchelon( f, a, b, m ) % input : f : function handler % a : the lowe ...
- Python实战(2)
在安装python第三方插件库的时候遇到了这个错误 遇到这种问题可以”转战“国内的第三方镜像,问题便可迎刃而解.例如豆瓣镜像——http://pypi.douban.com/simple/ 先安装ea ...
- VBS基础篇 - 运算符
VBScript 有一套完整的运算符,包括算术运算符.比较运算符.连接运算符和逻辑运算符. 运算符优先级: 首先计算算术运算符,然后计算比较运算符,最后计算逻辑运算符. 所有比较运算符的优先级相同,即 ...
- python学习小结6:模块
模块:在Python中有一个概念叫做模块(module),简单地说,模块就是一个保存了Python代码的文件. 模块能定义函数,类和变量,模块里也能包含可执行的代码. ...
- Oracle 多行记录合并/连接/聚合字符串的几种方法
怎么合并多行记录的字符串,一直是oracle新手喜欢问的SQL问题之一,关于这个问题的帖子我看过不下30个了,现在就对这个问题,进行一个总结.-什么是合并多行字符串(连接字符串)呢,例如: SQL&g ...
- android camera2 Api(转载)
现在的手机一般都会提供相机功能,有些相机的镜头甚至支持1000万以上像素,有些甚至支持光学变焦,这些手机已经变成了专业数码相机.为了充分利用手机上的相机功能,Android应用可以控制拍照和录制视频. ...