有了前面模板函数的铺垫,我们再来看模板类。对于模板类,大家了解基本用法即可,特别是模板类的使用方法,因为后续介绍的标准模板库STL中的容器都是基于模板类来实现的。
首先我们来看一个普通的类:
#include<iostream>
using namespace std;
#define ARR_MAX 10000
class MyList{
private:
int arr[ARR_MAX];
int len;
public:
MyList(){
this->len = 0;
}
//末尾追加元素
void append(int one){
this->arr[this->len] = one;
this->len++;
}
//输出所有元素
void print(){
for(int i=0;i<this->len;i++)
cout<<this->arr[i]<<" ";
cout<<endl;
}
//找到最大元素
int max(){
if(this->len==0)
cout<<"ERROR"<<endl;
int ret = this->arr[0];
for(int i=1;i<this->len;i++)
if(ret<this->arr[i])
ret = this->arr[i];
return ret;
}
};
int main()
{
MyList ml;
for(int i=1;i<=10;i++){
ml.append(i);
cout<<ml.max()<<endl;
}
ml.print();
return 0;
}
#include<iostream>
using namespace std;
#define ARR_MAX 10000
class MyList{
private:
int arr[ARR_MAX];
int len;
public:
MyList(){
this->len = 0;
}
//末尾追加元素
void append(int one){
this->arr[this->len] = one;
this->len++;
}
//输出所有元素
void print(){
for(int i=0;i<this->len;i++)
cout<<this->arr[i]<<" ";
cout<<endl;
}
//找到最大元素
int max(){
if(this->len==0)
cout<<"ERROR"<<endl;
int ret = this->arr[0];
for(int i=1;i<this->len;i++)
if(ret<this->arr[i])
ret = this->arr[i];
return ret;
}
};
int main()
{
MyList ml;
for(int i=1;i<=10;i++){
ml.append(i);
cout<<ml.max()<<endl;
}
ml.print();
return 0;
}
#include<iostream> using namespace std; #define ARR_MAX 10000 class MyList{ private: int arr[ARR_MAX]; int len; public: MyList(){ this->len = 0; } //末尾追加元素 void append(int one){ this->arr[this->len] = one; this->len++; } //输出所有元素 void print(){ for(int i=0;i<this->len;i++) cout<<this->arr[i]<<" "; cout<<endl; } //找到最大元素 int max(){ if(this->len==0) cout<<"ERROR"<<endl; int ret = this->arr[0]; for(int i=1;i<this->len;i++) if(ret<this->arr[i]) ret = this->arr[i]; return ret; } }; int main() { MyList ml; for(int i=1;i<=10;i++){ ml.append(i); cout<<ml.max()<<endl; } ml.print(); return 0; }
类MyList
就像一个功能简单的“队列”,可以使用append
成员函数向队列末尾添加新的int元素,可以使用max
成员函数找出队列中的最大值,还可以使用print
成员函数输出队列中的所有元素。队列的所有元素实际存储在成员变量int arr[ARR_MAX]
数组中,还有一个成员变量len
用来记录队列长度。
但是这个”队列“能处理的基本元素是int类型的数据,如果要处理double类型、string类型的元素,我们会想到再定义对应的类:
#include<iostream>
using namespace std;
#define ARR_MAX 10000
class MyList{
private:
double arr[ARR_MAX];
int len;
public:
MyList(){
len = 0;
}
//末尾追加元素(参数是double)
void append(double one){
arr[len] = one;
len++;
}
//输出所有元素
void print(){
for(int i=0;i<len;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
//找到最大元素(返回值是double)
double max(){
if(len==0)
cout<<"ERROR"<<endl;
double ret = arr[0];
for(int i=1;i<len;i++)
if(ret<arr[i])
ret = arr[i];
return ret;
}
};
int main()
{
MyList ml;
for(int i=1;i<=10;i++){
ml.append(1.0/i);
cout<<ml.max()<<endl;
}
ml.print();
return 0;
}
#include<iostream>
using namespace std;
#define ARR_MAX 10000
class MyList{
private:
double arr[ARR_MAX];
int len;
public:
MyList(){
len = 0;
}
//末尾追加元素(参数是double)
void append(double one){
arr[len] = one;
len++;
}
//输出所有元素
void print(){
for(int i=0;i<len;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
//找到最大元素(返回值是double)
double max(){
if(len==0)
cout<<"ERROR"<<endl;
double ret = arr[0];
for(int i=1;i<len;i++)
if(ret<arr[i])
ret = arr[i];
return ret;
}
};
int main()
{
MyList ml;
for(int i=1;i<=10;i++){
ml.append(1.0/i);
cout<<ml.max()<<endl;
}
ml.print();
return 0;
}
#include<iostream> using namespace std; #define ARR_MAX 10000 class MyList{ private: double arr[ARR_MAX]; int len; public: MyList(){ len = 0; } //末尾追加元素(参数是double) void append(double one){ arr[len] = one; len++; } //输出所有元素 void print(){ for(int i=0;i<len;i++) cout<<arr[i]<<" "; cout<<endl; } //找到最大元素(返回值是double) double max(){ if(len==0) cout<<"ERROR"<<endl; double ret = arr[0]; for(int i=1;i<len;i++) if(ret<arr[i]) ret = arr[i]; return ret; } }; int main() { MyList ml; for(int i=1;i<=10;i++){ ml.append(1.0/i); cout<<ml.max()<<endl; } ml.print(); return 0; }
#include<iostream>
using namespace std;
#define ARR_MAX 10000
class MyList{
private:
string arr[ARR_MAX];
int len;
public:
MyList(){
len = 0;
}
//末尾追加元素(参数是string)
void append(string one){
arr[len] = one;
len++;
}
//输出所有元素
void print(){
for(int i=0;i<len;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
//找到最大元素(返回值是string)
string max(){
if(len==0)
cout<<"ERROR"<<endl;
string ret = arr[0];
for(int i=1;i<len;i++)
if(ret<arr[i])
ret = arr[i];
return ret;
}
};
int main()
{
MyList ml;
for(int i=1;i<=10;i++){
string s; cin>>s;
ml.append(s);
cout<<ml.max()<<endl;
}
ml.print();
return 0;
}
#include<iostream>
using namespace std;
#define ARR_MAX 10000
class MyList{
private:
string arr[ARR_MAX];
int len;
public:
MyList(){
len = 0;
}
//末尾追加元素(参数是string)
void append(string one){
arr[len] = one;
len++;
}
//输出所有元素
void print(){
for(int i=0;i<len;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
//找到最大元素(返回值是string)
string max(){
if(len==0)
cout<<"ERROR"<<endl;
string ret = arr[0];
for(int i=1;i<len;i++)
if(ret<arr[i])
ret = arr[i];
return ret;
}
};
int main()
{
MyList ml;
for(int i=1;i<=10;i++){
string s; cin>>s;
ml.append(s);
cout<<ml.max()<<endl;
}
ml.print();
return 0;
}
#include<iostream> using namespace std; #define ARR_MAX 10000 class MyList{ private: string arr[ARR_MAX]; int len; public: MyList(){ len = 0; } //末尾追加元素(参数是string) void append(string one){ arr[len] = one; len++; } //输出所有元素 void print(){ for(int i=0;i<len;i++) cout<<arr[i]<<" "; cout<<endl; } //找到最大元素(返回值是string) string max(){ if(len==0) cout<<"ERROR"<<endl; string ret = arr[0]; for(int i=1;i<len;i++) if(ret<arr[i]) ret = arr[i]; return ret; } }; int main() { MyList ml; for(int i=1;i<=10;i++){ string s; cin>>s; ml.append(s); cout<<ml.max()<<endl; } ml.print(); return 0; }
有了前面模板函数的思路,可知这样的做法不够简洁,其实这里可以使用模板类来处理基本元素是int、double、string,甚至是前面提到的Circle类的情况:
#include<iostream>
using namespace std;
#define ARR_MAX 10000
//和模板函数一样,这里指明模板类中会使用的通用数据类型T
template<typename T>
class MyList{
private:
T arr[ARR_MAX]; //数组元素是T类型
int len;
public:
MyList(){
len = 0;
}
//末尾追加元素(参数是T类型)
void append(T one){
arr[len] = one;
len++;
}
//输出所有元素
void print(){
for(int i=0;i<len;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
//找到最大元素(返回值是T类型)
T max(){
if(len==0)
cout<<"ERROR"<<endl;
T ret = arr[0];
for(int i=1;i<len;i++)
if(ret<arr[i])
ret = arr[i];
return ret;
}
};
int main()
{
//注意模板类变量的定义方法
//需要显示地指定通用类型T的实际类型
MyList<int> ml1;
for(int i=1;i<=10;i++){
ml1.append(i);
cout<<ml1.max()<<endl;
}
ml1.print();
MyList<double> ml2;
for(int i=1;i<=10;i++){
ml2.append(1.0/i);
cout<<ml2.max()<<endl;
}
ml2.print();
MyList<string> ml3;
for(int i=1;i<=10;i++){
string s; cin>>s;
ml3.append(s);
cout<<ml3.max()<<endl;
}
ml3.print();
return 0;
}
#include<iostream>
using namespace std;
#define ARR_MAX 10000
//和模板函数一样,这里指明模板类中会使用的通用数据类型T
template<typename T>
class MyList{
private:
T arr[ARR_MAX]; //数组元素是T类型
int len;
public:
MyList(){
len = 0;
}
//末尾追加元素(参数是T类型)
void append(T one){
arr[len] = one;
len++;
}
//输出所有元素
void print(){
for(int i=0;i<len;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
//找到最大元素(返回值是T类型)
T max(){
if(len==0)
cout<<"ERROR"<<endl;
T ret = arr[0];
for(int i=1;i<len;i++)
if(ret<arr[i])
ret = arr[i];
return ret;
}
};
int main()
{
//注意模板类变量的定义方法
//需要显示地指定通用类型T的实际类型
MyList<int> ml1;
for(int i=1;i<=10;i++){
ml1.append(i);
cout<<ml1.max()<<endl;
}
ml1.print();
MyList<double> ml2;
for(int i=1;i<=10;i++){
ml2.append(1.0/i);
cout<<ml2.max()<<endl;
}
ml2.print();
MyList<string> ml3;
for(int i=1;i<=10;i++){
string s; cin>>s;
ml3.append(s);
cout<<ml3.max()<<endl;
}
ml3.print();
return 0;
}
#include<iostream> using namespace std; #define ARR_MAX 10000 //和模板函数一样,这里指明模板类中会使用的通用数据类型T template<typename T> class MyList{ private: T arr[ARR_MAX]; //数组元素是T类型 int len; public: MyList(){ len = 0; } //末尾追加元素(参数是T类型) void append(T one){ arr[len] = one; len++; } //输出所有元素 void print(){ for(int i=0;i<len;i++) cout<<arr[i]<<" "; cout<<endl; } //找到最大元素(返回值是T类型) T max(){ if(len==0) cout<<"ERROR"<<endl; T ret = arr[0]; for(int i=1;i<len;i++) if(ret<arr[i]) ret = arr[i]; return ret; } }; int main() { //注意模板类变量的定义方法 //需要显示地指定通用类型T的实际类型 MyList<int> ml1; for(int i=1;i<=10;i++){ ml1.append(i); cout<<ml1.max()<<endl; } ml1.print(); MyList<double> ml2; for(int i=1;i<=10;i++){ ml2.append(1.0/i); cout<<ml2.max()<<endl; } ml2.print(); MyList<string> ml3; for(int i=1;i<=10;i++){ string s; cin>>s; ml3.append(s); cout<<ml3.max()<<endl; } ml3.print(); return 0; }
我们可以进一步改造前面提到的Circle
类,重载<
运算符并重载ostream
运算符(用于cout输出),这样模板类MyList
也能处理Circle
类型的元素:
#include<iostream>
using namespace std;
#define ARR_MAX 10000
#define PI 3.14159
class Circle{
public:
double r;
Circle(){
r = 0;
}
Circle(double r){
this->r = r;
}
double length() const{
return 2*PI*r;
}
double area() const{
return PI*r*r;
}
};
//重载<运算符
bool operator <(const Circle &a,const Circle &b){
return a.r < b.r;
}
//重载ostream运算符,可以直接用cout输出Circle变量
//输出圆的半径、周长、面积信息(三元组形式)
ostream& operator<<(ostream &os,const Circle &c){
os<<"("<<c.r<<" "<<c.length()<<" "<<c.area()<<")";
return os;
}
//和模板函数一样,这里指明模板类中会使用的通用数据类型T
template<typename T>
class MyList{
private:
T arr[ARR_MAX]; //数组元素是T类型
int len;
public:
MyList(){
len = 0;
}
//末尾追加元素(参数是T类型)
void append(T one){
arr[len] = one;
len++;
}
//输出所有元素
void print(){
for(int i=0;i<len;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
//找到最大元素(返回值是T类型)
T max(){
if(len==0)
cout<<"ERROR"<<endl;
T ret = arr[0];
for(int i=1;i<len;i++)
if(ret<arr[i])
ret = arr[i];
return ret;
}
};
int main()
{
MyList<Circle> ml;
for(int i=1;i<=10;i++){
ml.append(Circle(1.0*i));
cout<<ml.max()<<endl;
}
ml.print();
return 0;
}
#include<iostream>
using namespace std;
#define ARR_MAX 10000
#define PI 3.14159
class Circle{
public:
double r;
Circle(){
r = 0;
}
Circle(double r){
this->r = r;
}
double length() const{
return 2*PI*r;
}
double area() const{
return PI*r*r;
}
};
//重载<运算符
bool operator <(const Circle &a,const Circle &b){
return a.r < b.r;
}
//重载ostream运算符,可以直接用cout输出Circle变量
//输出圆的半径、周长、面积信息(三元组形式)
ostream& operator<<(ostream &os,const Circle &c){
os<<"("<<c.r<<" "<<c.length()<<" "<<c.area()<<")";
return os;
}
//和模板函数一样,这里指明模板类中会使用的通用数据类型T
template<typename T>
class MyList{
private:
T arr[ARR_MAX]; //数组元素是T类型
int len;
public:
MyList(){
len = 0;
}
//末尾追加元素(参数是T类型)
void append(T one){
arr[len] = one;
len++;
}
//输出所有元素
void print(){
for(int i=0;i<len;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
//找到最大元素(返回值是T类型)
T max(){
if(len==0)
cout<<"ERROR"<<endl;
T ret = arr[0];
for(int i=1;i<len;i++)
if(ret<arr[i])
ret = arr[i];
return ret;
}
};
int main()
{
MyList<Circle> ml;
for(int i=1;i<=10;i++){
ml.append(Circle(1.0*i));
cout<<ml.max()<<endl;
}
ml.print();
return 0;
}
#include<iostream> using namespace std; #define ARR_MAX 10000 #define PI 3.14159 class Circle{ public: double r; Circle(){ r = 0; } Circle(double r){ this->r = r; } double length() const{ return 2*PI*r; } double area() const{ return PI*r*r; } }; //重载<运算符 bool operator <(const Circle &a,const Circle &b){ return a.r < b.r; } //重载ostream运算符,可以直接用cout输出Circle变量 //输出圆的半径、周长、面积信息(三元组形式) ostream& operator<<(ostream &os,const Circle &c){ os<<"("<<c.r<<" "<<c.length()<<" "<<c.area()<<")"; return os; } //和模板函数一样,这里指明模板类中会使用的通用数据类型T template<typename T> class MyList{ private: T arr[ARR_MAX]; //数组元素是T类型 int len; public: MyList(){ len = 0; } //末尾追加元素(参数是T类型) void append(T one){ arr[len] = one; len++; } //输出所有元素 void print(){ for(int i=0;i<len;i++) cout<<arr[i]<<" "; cout<<endl; } //找到最大元素(返回值是T类型) T max(){ if(len==0) cout<<"ERROR"<<endl; T ret = arr[0]; for(int i=1;i<len;i++) if(ret<arr[i]) ret = arr[i]; return ret; } }; int main() { MyList<Circle> ml; for(int i=1;i<=10;i++){ ml.append(Circle(1.0*i)); cout<<ml.max()<<endl; } ml.print(); return 0; }
和模板函数相似,模板类不是实际的类,而是编译器用于生成一个或多个类的 "模具"。在编写模板类时,不必指定实际数据类型,而是使用类型名称(上面的typename T
)来指定通用数据类型。当编译器遇到对模板类的定义时,它将检查定义语句处的数据类型,并对照模板类的实现代码生成与数据类型相对应的实际类代码。
综上所述,对于模板类,需要通过:类名<实际数据类型> 变量名;
的方式来定义模板类变量。例如前面示例代码中出现的:
MyList<int> ml1;
MyList<double> ml2;
MyList<string> ml3;
MyList<Circle> ml;
MyList<int> ml1;
MyList<double> ml2;
MyList<string> ml3;
MyList<Circle> ml;
MyList<int> ml1; MyList<double> ml2; MyList<string> ml3; MyList<Circle> ml;
记住这样的语法形式,后面介绍的STL容器会大量使用这样的语法形式定义容器变量。