C++模板
一 定义
函数模板:定义用来生成一组具体函数配方的代码。
模板是对具有相同特性的函数或类的再抽象。
1.它是一种参数化多态性的工具,可以为逻辑功能相同 而类型不同的程序提供一种代码共享的机制。
2.一个模板并非一个实实在在的类或函数,仅仅是一个 类或函数的描述,是参数化的函数和类。
3.模板分为函数模板和类模板,通过参数实例化可以再 构造出具体的函数或类,称为模板函数和模板类。
二 函数模板和 模板函数
template <模板参数表 > 返回值类型 函数名 (参数表) { 函数体 }
// 使用max( )函数模板的位置范例 #include <iostream> using std::cout; using std::endl; template <class T> T max(T x[], int len)//注意前后连在一起 { T maxnumber = x[0]; for (int i = 0; i < len; i++) if (maxnumber < x[i]) maxnumber = x[i]; return maxnumber; } int main(void) { int small[] = { 1, 24 , 34 , 22 }; long medium[] = { 23, 245, 123, 1, 234, 2345 }; double large[] = { 23.0, 1.4, 2.456, 345.5, 12.0, 21.0 }; int lensmall = sizeof small / sizeof small[0]; int lenmedium = sizeof medium / sizeof medium[0]; int lenlarge = sizeof large / sizeof large[0]; cout << endl << max(small, lensmall); cout << endl << max(medium, lenmedium); cout << endl << max(large, lenlarge); cout << endl; return 0; } /* 34 2345 345.5 */
一般情况下typename和class基本没有什么区别。
函数模板
当编译系统在程序中发现有与函数模板中相匹配的函 数调用时,便生成一个重载函数,该重载函数的函数 体与函数模板的函数体相同。
该重载函数称为模板函数。它是函数模板的一个具体 实例,只处理一种惟一的数据类型。
// 重载模板函数实例,例题8.2 #include <iostream> #include <string.h> using namespace std; template <typename T> T Max(T a, T b) { return a > b ? a : b; } char * Max(char *pa, char *pb) { return strcmp(pa, pb) ? pa : pb; } int main() { cout << Max(10, 20) << endl; cout << Max("Hello", "Fellow") << endl; cin.ignore(); return 0; }
为什么不直接用模板函数,而是 重载模板函数的理由? 答:因为字符串的比较方法是不 同的,无法使用模板函数,必须 重载
模板函数的重载的又一示例
// 模板函数与学生类的实例,例题8.3 #include <iostream> #include <string.h> using namespace std; template <typename T> T Max(T a, T b) { return a > b ? a : b; } class Student { int number; char name[20]; public:Student(int i, char *s) { number = i; strcpy(name, s); } bool operator>(Student &st) //重载运算符> { return number > st.number; //返回成员number的比较结果 } void Print() { cout << "Number: " << number << endl; cout << "Name: " << name << endl; } }; int main() { Student st1(12, "Li"), st2(13, "Zhang"), st3(0, ""); st3 = Max(st1, st2); st3.Print(); cin.ignore(); return 0; } /* Number: 13 Name: Zhang */
三 类模板和 模板类
类模板:不是类,是编译器用来生成类代码的类的框架。 用类模板创建出来的类被称为类模板的实例。
template <类型参数表> 返回值类型 类模板名 类型名表::函数名(参数表) { 函数体 }
类模板的使用
类模板名 <实际的类型>
类模板名 <实际的类型> <对象名>[(实际参数表)];CSamples myData(10.0);
// 使用CSample的范例程序 #include <iostream> using namespace std; // 定义一个箱子类 class CBox { public: // 构造函数:确保长比宽的数值大 CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0) :m_Height(hv) { m_Length = lv > wv ? lv : wv; m_Width = wv < lv ? wv : lv; } double Volume() const // 计算体积函数 { return m_Length * m_Width*m_Height; }// >重载:比较CBox类型的两个对象 int CBox::operator>(const CBox& aBox)const { return this->Volume() > aBox.Volume(); } // >重载:比较CBox类型对象和double数据 int operator>(const double& value) const { return Volume() > value; } CBox operator+(const CBox& aBox) const { return CBox(m_Length > aBox.m_Length ? m_Length : aBox.m_Length, m_Width > aBox.m_Width ? m_Width : aBox.m_Width, m_Height + aBox.m_Height); }void ShowBox()const { cout << m_Length << " " << m_Width << " " << m_Height << endl; } private: double m_Length; double m_Width; double m_Height; };// 定义Csample类模板 template <class T> class CSamples { public: CSamples(const T values[], int count); CSamples(const T& value); CSamples() { m_Free = 0; } bool Add(const T& value); T Max() const; private: T m_Values[100]; int m_Free; };//接受数组形式样本数据的构造函数 template <class T> CSamples<T>::CSamples(const T values[], int count) { m_Free = count < 100 ? count : 100; for (int i = 0; i < m_Free; i++) m_Values[i] = values[i]; } //接受单个样本数据的构造函数 template <class T> CSamples<T>::CSamples(const T& value) { m_Values[0] = value; m_Free = 1; }//添加一个样本数据成员函数 template <class T> bool CSamples<T>::Add(const T& value) { bool OK = m_Free < 100; if (OK) m_Values[m_Free++] = value; } //提取最大样本数据的成员函数 template <class T> T CSamples<T>::Max() const { T theMax = m_Free ? m_Values[0] : 0; for (int i = 1; i < m_Free; i++) if (m_Values[i] > theMax) theMax = m_Values[i]; return theMax; }int main() { CBox boxes[] = { CBox(8.0, 5.0, 2.0), CBox(5.0, 4.0, 6.0), CBox(4.0, 3.0, 3.0) }; //使用数组初始化一个可以存储CBox对象的CSamples对象 CSamples <CBox> myBoxes(boxes, sizeof(boxes) / sizeof(CBox)); //计算最大的箱子 CBox maxBox = myBoxes.Max(); //输出结果 cout << endl << "The biggest box has a volume of " << maxBox.Volume() << endl; cin.ignore(); return 0; } /* The biggest box has a volume of 120 */
类模板的使用的注意事项
创建类模板的实例时,编译器只创建 程序中实际调用 的成员函数的模板实例;不能理解成用于创建函数成员的 那些函数模板的实例也将被创建。
因此,函数模板甚至可以包含编译错误,而且只要不调 用该模板生成的成员函数,编译器不会有什么抱怨;
例如, 在前面的例子中的Add( )成员的模板中引入错误,该程序 仍然可以编译和执行。
一个小问题:CBox类的构造函数被调用了多少次? 答案是103次!
主函数中创建了包含3个CBox对象的数组,发生3次调 用;
其后创建了一个容纳这些对象的CSamples对象,但 CSamples对象包含的数组有100个CBox类型的变量,因此 需要再调用默认构造函数100次。
使用包含多个形参的类模板
如这样的类模板
template Class CExampleClass { private: T1 m_Value1; T2 m_Value2; …… };