类属性用于实现参数化模块,即,给程序模块加上类型参数,使其能对不同类型的数据实施相同的操作,它是多态的一种形式。
在C++中,类属性主要体现在类属函数和类属类中。
1.函数模板
例:排序用函数模板来实现。
template <class T>
void sort(T elements[], unsigned int count)
{ //取第i个元素
elements [i]
//比较第i个和第j个元素的大小
elements [i] < elements [j]
//交换第i个和第j个元素
T temp=elements [i];
elements [i] = elements [j];
elements [j] = temp;
}
......
int a[100];
sort(a,100);
double b[200];
sort(b,200);
A c[300]; //类A中需重载操作符:<和=,给出拷贝构造函数
sort(c,300);
函数模板定义了一类重载的函数,使用函数模板所定义的函数(模板函数)时,编译系统会自动把函数模板实例化。
模板的参数可以有多个,用逗号分隔它们,如:
template <class T1, class T2>
void f(T1 a, T2 b)
{ ......
}
模板也可以带普通参数,它们须放在类型参数的后面,调用时需显式实例化,如:
template <class T, int size>
void f(T a)
{ T temp[size];
......
}
void main()
{ f<int,10>(1);
}
有时,需要把函数模板与函数重载结合起来用,例如:
template <class T>
T max(T a, T b)
{ return a>b?a:b;
}
…
int x,y,z;
double l,m,n;
z = max(x,y);
l = max(m,n);
问题:max(x,m)如何处理?
定义一个max的重载函数:
double max(int a,double b)
{ return a>b?a:b;
}
2 类属类
类定义带有类型参数,一般用类模板实现。
例:定义一个栈类,其元素类型可以变化。
template <class T>
class Stack
{ T buffer[100];
public:
void push(T x);
T pop();
};
template <class T>
void Stack <T>::push(T x) { … }
template <class T>
T Stack <T>::pop() { … }
……
Stack <int> st1;
Stack <double> st2;
类模板定义了若干个类,类模板的实例化是显式的。
类模板的参数可以有多个,其中包括普通参数,用逗号分隔它们。并且普通参数须放在类型参数的后面。
例:定义不同大小的栈模板
template <class T, int size>
class Stack
{ T buffer[size];
public:
void push(T x);
T pop();
};
template <class T,int size>
void Stack <T,size>::push(T x) { … }
template <class T, int size>
T Stack <T,size>::pop() { … }
……
Stack <int,100> st1;
Stack <double,200> st2;
注意:1)类模板不能嵌套(局部类模板)。
2)类模板中的静态成员仅属于实例化后的类(模板类),不同实例之间不存在共享。
3 模板也是一种代码复用机制
模板提供了代码复用。在使用模板时首先要实例化,即生成一个具体的函数或类。函数模板的实例化是隐式实现的,即由编译系统根据对具体模板函数(实例化后的函数)的调用来进行相应的实例化,而类模板的实例化是显式进行的,在创建对象时由程序指定。
一个模板有很多实例,是否实例化模板的某个实例由使用点来决定,如果未使用到一个模板的某个实例,则编译系统不会生成相应实例的代码。
在C++中,由于模块是分别编译的,如果在模块A中要使用模块B中定义的一个模板的某个实例,而在模块B中未使用这个实例,则模块A无法使用这个实例,除非在模块A中也定义了相应的模板。因此模板是基于源代码复用,而不是目标代码复用。
例:
// file1.h
template <class T>
class S
{ T a;
public:
void f();
};
// file1.cpp
#include "file1.h"
template <class T>
void S<T>::f()
{ …
}
template <class T>
T max(T x, T y)
{ return x>y?x:y;
}
void main()
{ int a,b;
float m,n;
max(a,b);
max(m,n);
S<int> x;
x.f();
}
// file2.cpp
#include "file1.h"
extern double max(double,double);
void sub()
{ max(1.1,2.2); //Error,no appropriate instance
S<float> x;
x.f(); //Error, corresponding instance has no appropriate implementation
}
在C++中,类属性主要体现在类属函数和类属类中。
1.函数模板
例:排序用函数模板来实现。
template <class T>
void sort(T elements[], unsigned int count)
{ //取第i个元素
elements [i]
//比较第i个和第j个元素的大小
elements [i] < elements [j]
//交换第i个和第j个元素
T temp=elements [i];
elements [i] = elements [j];
elements [j] = temp;
}
......
int a[100];
sort(a,100);
double b[200];
sort(b,200);
A c[300]; //类A中需重载操作符:<和=,给出拷贝构造函数
sort(c,300);
函数模板定义了一类重载的函数,使用函数模板所定义的函数(模板函数)时,编译系统会自动把函数模板实例化。
模板的参数可以有多个,用逗号分隔它们,如:
template <class T1, class T2>
void f(T1 a, T2 b)
{ ......
}
模板也可以带普通参数,它们须放在类型参数的后面,调用时需显式实例化,如:
template <class T, int size>
void f(T a)
{ T temp[size];
......
}
void main()
{ f<int,10>(1);
}
有时,需要把函数模板与函数重载结合起来用,例如:
template <class T>
T max(T a, T b)
{ return a>b?a:b;
}
…
int x,y,z;
double l,m,n;
z = max(x,y);
l = max(m,n);
问题:max(x,m)如何处理?
定义一个max的重载函数:
double max(int a,double b)
{ return a>b?a:b;
}
2 类属类
类定义带有类型参数,一般用类模板实现。
例:定义一个栈类,其元素类型可以变化。
template <class T>
class Stack
{ T buffer[100];
public:
void push(T x);
T pop();
};
template <class T>
void Stack <T>::push(T x) { … }
template <class T>
T Stack <T>::pop() { … }
……
Stack <int> st1;
Stack <double> st2;
类模板定义了若干个类,类模板的实例化是显式的。
类模板的参数可以有多个,其中包括普通参数,用逗号分隔它们。并且普通参数须放在类型参数的后面。
例:定义不同大小的栈模板
template <class T, int size>
class Stack
{ T buffer[size];
public:
void push(T x);
T pop();
};
template <class T,int size>
void Stack <T,size>::push(T x) { … }
template <class T, int size>
T Stack <T,size>::pop() { … }
……
Stack <int,100> st1;
Stack <double,200> st2;
注意:1)类模板不能嵌套(局部类模板)。
2)类模板中的静态成员仅属于实例化后的类(模板类),不同实例之间不存在共享。
3 模板也是一种代码复用机制
模板提供了代码复用。在使用模板时首先要实例化,即生成一个具体的函数或类。函数模板的实例化是隐式实现的,即由编译系统根据对具体模板函数(实例化后的函数)的调用来进行相应的实例化,而类模板的实例化是显式进行的,在创建对象时由程序指定。
一个模板有很多实例,是否实例化模板的某个实例由使用点来决定,如果未使用到一个模板的某个实例,则编译系统不会生成相应实例的代码。
在C++中,由于模块是分别编译的,如果在模块A中要使用模块B中定义的一个模板的某个实例,而在模块B中未使用这个实例,则模块A无法使用这个实例,除非在模块A中也定义了相应的模板。因此模板是基于源代码复用,而不是目标代码复用。
例:
// file1.h
template <class T>
class S
{ T a;
public:
void f();
};
// file1.cpp
#include "file1.h"
template <class T>
void S<T>::f()
{ …
}
template <class T>
T max(T x, T y)
{ return x>y?x:y;
}
void main()
{ int a,b;
float m,n;
max(a,b);
max(m,n);
S<int> x;
x.f();
}
// file2.cpp
#include "file1.h"
extern double max(double,double);
void sub()
{ max(1.1,2.2); //Error,no appropriate instance
S<float> x;
x.f(); //Error, corresponding instance has no appropriate implementation
}