NOIP学习小站
西安交通大学附属中学航天学校

模板类

有了前面模板函数的铺垫,我们再来看模板类。对于模板类,大家了解基本用法即可,特别是模板类的使用方法,因为后续介绍的标准模板库STL中的容器都是基于模板类来实现的。

首先我们来看一个普通的类:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#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类型的元素,我们会想到再定义对应的类:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#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; 
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#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类的情况:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#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类型的元素:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#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)来指定通用数据类型。当编译器遇到对模板类的定义时,它将检查定义语句处的数据类型,并对照模板类的实现代码生成与数据类型相对应的实际类代码。

综上所述,对于模板类,需要通过:类名<实际数据类型> 变量名;的方式来定义模板类变量。例如前面示例代码中出现的:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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容器会大量使用这样的语法形式定义容器变量。