(41.1)类模板之类模板的定义

1.类模板的定义

  • 如何避免类似下面的重复性的工作?
class Compare_int
{
	public :
		Compare(int a,int b){x=a;y=b;}//构造函数
		float max(){return (x>y)?x:y;}//求最大值
		float min(){return (x<y)?x:y;}//求最小值
	private :
		int x,y;
}

class Compare_double
{
	public :
		Compare(double a,double b){x=a;y=b;}//构造函数
		float max(){return (x>y)?x:y;}//求最大值
		float min(){return (x<y)?x:y;}//求最小值
	private :
		double x,y;
}
  • 就像可以定义函数模板一样, 也可以定义类模板。 其定义的一般形式为:
template <模板形参表>
class 类模板名 
{//类体
	成员列表
};
  • 类模板必须以关键字template开头, 后接模板形参表。
    模板形参表是用一对尖括号< >括住的一个或多个模板形参的列表, 不允许为空, 形参之间以逗号分隔。
    其一般形式为:
<class 类型参数1, class 类型参数2, ...... >
  • 模板形参表用于表示可以在类定义中使用的数据类型。 类型形参跟在关键字class或typename之后定义, 如class T是名为T的类型形参,在这里class和typename没有区别。
    一般地, 类模板习惯用class,函数模板习惯用typename。
  • 除了模板形参列表外, 类模板的定义与类定义相似。
    类模板可以定义数据成员和函数成员, 也可以使用访问标号控制对成员的访问,还可以定义构造函数和析构函数等等。
    在类和类成员的定义中, 可以使用模板形参作为类型或值的占位符, 在使用类时再提供那些类型或值的具体信息。
  • 由于类模板包含类型参数, 因此又称为参数化的类。 如果说类是对象的抽象, 对象是类的实例, 则类模板是类的抽象, 类是类模板的实例。
    利用类模板可以建立支持各种数据类型的类。
  • eg:例如定义一个类模板表示平面上的点:
template <class T> //类模板定义
class Point 
{ //Point不是类名是模板名
	public:
		Point() : x(0), y(0) { } //默认构造函数
		Point(const T a, const T b) : x(a), y(b) { } //带参数构造函数
		void Set(const T a, const T b);
		void Display()
		{ 
			cout<<"Display: "<<"x="<<x<<",y="<<y<<endl; 
		}
	private:
		T x, y;
};
  • 如果在类模板外部定义成员函数, 形式为:
template <模板形参表>
返回类型 类名<类型参数表>::函数名(形式参数列表)
{
	函数体
}

eg:
template <class T>
void Point<T>::Set(const T a, const T b) //属于类模板里面的成员函数
{
	x=a , y=b;
}
  • 用类模板定义对象时, 必须为模板形参显式指定类型实参, 一般形式为:
类模板名<类型实参表> 对象名列表;
类模板名<类型实参表> 对象名1(实参列表1), 对象名2(实参列表2),......;
  • eg:
Point <int> a, b; //定义类模板对象, 调用默认构造函数
Point <double> m(1,2), n(3,4); //定义类模板对象 , 调用带参数构造函数,对象m和n里面的数据成员都是double类型的
  • 模板形参表还可以是非类型形参, 其形式与函数形参表相似。
    例如:
template <class T, int N>//T表示T类型
class Sequence 
{ //Sequence类模板
	public:
		void Set(int i, T value);
		T Get(int i) { return array[i]; }
	private:
		T array[N];
};
template <class T, int N>
void Sequence<T,N>::Set(int i, T value)//属于Sequence类类型的实参
{ 
	array[i]=value; 
}
  • 当定义类模板对象时, 必须为每个非类型形参提供常量表达式以供使用。
    例如:
Sequence <int,5> a; //提供类型和常量表达式,int对应T,5对应大写的N,数据是int型的,长度为5
Sequence <double,5> b; //提供类型和常量表达式
for(i=0;i<5;i++) a.Set(i,i); //给a的数组成员赋值
for(i=0;i<5;i++) cout<<a.Get(i)<<" "; //输出数组成员的值
  • 模板形参还可以设置默认值。 例如:
template <class T=char , int N=10> //类模板定义
class Sequence 
{};

eg:
则对象定义时可以有以下形式:
Sequence <> m; //使用默认类型char和使用默认值10
Sequence <double> n; //提供类型和使用默认值10
Sequence <int,100> k; //提供类型和常量表达式

2.标准C++为此提供了关键字export, 其作用与extern相似

  • 这样, 函数模板或类模板的实例化与定义体可以不必放在同一个编译单元了。
extern int n; //声明整型n, 变量定义在另一个编译单元

extern struct Point p; //实例化结构体对象p, 结构体定义在另一个编译单元

extern class Stack s; //实例化类对象s, 类定义在另一个编译单元

export template<class T>class A<int> a; //实例化类模板对象a, 类模板定义在另一个编译单元

export template<class T>void f (T& t);//实例化函数模板f,函数模板定义在另一个编译单元
  • 类模板在表示数组、 向量、 列表、 队列、 栈、 矩阵等数据结构时,显得特别重要, 因为这些数据结构的表示和算法的选择不受其所包含的元素的类型的影响
发布了556 篇原创文章 · 获赞 140 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/u011436427/article/details/104302569