本文最后更新于:1 年前
(一)函数模版:
重载函数通常基于不同的数据类型实现类似的操作,对不同数据类型有完全相同的操作,用函数模版实现更为简介方便。
1. 格式与定义:
template <类型形式参数表>
返回类型 函数名(参数列表) { 函数体 }
类型形式参数表= class T1, class T2, ... , class Tn or typename T1, typename T2, ... , typename Tn
函数模版定义由模版说明和函数定义构成。
模版说明的类属参数必须在函数定义中至少出现一次。
函数参数表中可以使用类属类型参数,也可以使用一般类型参数。
函数模板不允许自动类型转化。
其他要点前文已有讲述,此处不再重复。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include<iostream> using namespace std; template <typename T> bool IsEqual(const T& left, const T& right) { return left == right; }
template <typename T1,typename T2> bool IsEqual2(const T1& left, const T2& right) { return left == right; }
int main() { cout << IsEqual(1, 1) << endl; cout << IsEqual<int>(1, 1.2) << endl; cout << IsEqual<double>(1, 1.2) << endl;
cout << IsEqual2(1, 1) << endl; cout << IsEqual2(1,1.2)<<endl; cout << IsEqual2<int,double>(1, 1.2) << endl; cout << IsEqual2<double,int>(1, 1.2) << endl; return 0; }
|
2. 重载函数模版:
当模版类型不能满足需要(不能提供类型的隐式转换)时,函数模版可以进行重载(效果和普通的函数重载一致),而且可以和普通重载函数并存。
此时如果均存在匹配,涉及到了匹配的优先级关系,为此,c++的函数模版有匹配约定:
-
寻找和使用最符合函数名和函数类型的普通函数,若找到则调用它。
-
否则寻找一个函数模版,将其实例化产生一个匹配的函数参数,若找到则调用它。
-
否则,寻找可以通过类型转换进行参数匹配的重载函数,若找到则调用它。
-
如果前三次的寻找均为找到匹配函数,则调用错误;如果在三次的某次寻找中调用有多余一个的匹配选择,则调用匹配出现二义性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| #include<iostream> using namespace std; bool IsEqual(const int& left,const int& right) { cout << "重载普通函数1" << endl; return left == right; }
bool IsEqual(const double& left, const double& right) { cout << "重载普通函数2" << endl; return left == right; }
template <typename T> bool IsEqual(const T& left, const T& right) { cout << "模版" << endl; return left == right; }
template <typename T1,typename T2> bool IsEqual(const T1& left, const T2& right) { cout << "重载模版1,参数类型不同" << endl; return left == right; }
template <typename T> bool IsEqual(const T& right) { cout << "重载模版2,参数个数不同" << endl; return 1 == right; }
int main() { cout << IsEqual(1, 1) << endl; cout << IsEqual(1,1.2)<<endl; cout << IsEqual(1.2, 1.2) << endl; cout << IsEqual(1.2, 1) << endl; cout << IsEqual("1", "1") << endl; cout << IsEqual<int,double>(1, 1) << endl; cout << IsEqual<double,int>(1, 1.2) << endl; cout << IsEqual<char>('1') << endl;; return 0; }
|
(二)类模版:
类模版用于实现类所需数据的类型参数化。
类模版在表示如数组、表、图等数据结构上显得特别重要,这些数据结构的表示和算法不受所包含的元素类型的影响。
1. 格式:
template<类型形式参数表>
class 类名{ ... };
类属参数可以用于声明类中的成员变量和成员函数,在类中使用内置雷类型的地方也都可以用类属参数来声明。
另外,类模版中的成员函数放到类模版定义外面写时的语法有限制:
template<类型形式参数表>
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表) { 函数体 }
创建对象的格式:
类模板名<真实类型参数表> 对象名(构造函数实际参数表);
如果有无参构造函数,可以是:
类模板名<真实类型参数表> 对象名;
注意:类模版形参不存在实参推演的问题,不能给真实类型参数表传递实参,只能传递类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| #include<iostream> using namespace std; template<class T> class Person { private: T mAge; T mID; public: Person(const Person<T>& a) { this->mAge = a.mAge; this->mID = a.mID; } Person() {} T getage() { return mAge; } T getmID() { return mID; } Person(T age, T id); void Show();
};
template<class T> Person<T>::Person(T age, T id) { this->mID = id; this->mAge = age; } template<class T> void Person<T>::Show() { cout << "Age:" << mAge << " ID:" << mID << endl; } int main() { Person<int> p1(10,20021111); Person<string>p2("15", "20031111"); Person<string>p3(p2); Person<char> p4; p1.Show(); p2.Show(); p3.Show(); cout << p1.getage() << endl; cout << p2.getmID() << endl; return 0; }
|
2. 类模版作为函数参数:
函数的形式参数类型可以是类模版或类模版的引用,对应的实际参数是该类模版实例化的模版类对象。
因此,只有函数模版能够拥有模版类参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include<iostream> using namespace std; template<class T> class Array { public: T n; };
template<class T> T funtest(Array<T> a) { cout << a.n << endl; return a.n; }
int main() { Array<int> a; a.n = 1; cout << funtest(a) << endl; return 0; }
|
3. 模板类和类模板:
类模板是模板的一种,可以在使用确定类属参数。
类模板不是一个类,不会生成对象,也不会占据空间。
模板类是类模板的一个实例,是确定了类属参数的具体类,可以直接生成对象。
1 2 3 4 5
| //模板类: //template<class T> //class Array {}; //类模板: Array<double> array;
|
4. 函数模板作为类模版成员:
类模板中的成员函数还可以是一个函数模板成员,函数模板只有在被调用时才会被实例化。
无论是原则还是声明,模板语法的优先级是最高的,不同模板的优先级先根据其声明顺序来判断,其次是函数修饰,然后是返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <iostream> using namespace std; template <class T> class A { public: template <class T2> void Func(T2 t) { cout << t << endl; return; } template <class T3> A<T> Func2(T3 t); }; template<class T3> template<class T> A<T3> A<T3>::Func2(T t) { cout << t << endl; return *this; } int main() { A<int> a; a.Func<int>('K'); a.Func("hello"); a.Func2("world"); return 0; }
|
5. 类层次中的类模版:
在类层次中,类模板可以是基类,也可以是派生类。
类模板可以从类模板或普通类派生:
普通类可以从模板类或普通类派生:
类模板之间允许有多继承关系(性质简单,此略)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
| #include <iostream> using namespace std;
template<class T> class Person { public: T age; Person() :age(5) {} void print() { cout << "age:" << age << endl; } };
class SubPerson : public Person<int> { public: double age; SubPerson() :age(10), Person() {} void print() { cout << "age:" << age << endl; } };
template<class T> class Animal { public: T age; Animal() :age(5) {} void print() { cout << "age" << age << endl; } }; template<class T, class T1> class Cat : public Animal<T> { public: T1 age; Cat() :Animal<T>(), age(10) {} void print() { cout << "age" << age << endl; } };
class Student { public: int age; Student() :age(5) {} void print() { cout << "age" << age << endl; } }; template<class T> class GoodStudent:public Student { public: T age; GoodStudent() :Student(), age(10) {} void print() { cout << "age" << age << endl; } };
int main(void) { Person<double> p; SubPerson pa; Animal<double> a; Cat<int,double> cat; Student s; GoodStudent<double> gs; p.print(); pa.print(); a.print(); cat.print(); s.print(); gs.print(); return 0; }
|
6. 类模版和友元:
模板类的友元分三类:
1,非模板友元。
2,约束模板友元,即友元的类型取决于类被实例化时的类型。
3,非约束模板友元,即友元的所有具体化都是类的每一个具体化的友元。
所有友元中的函数的参数或者返回值可以是该模板类的类属参数。
友元的内容十分复杂,具体内容详见代码的讲解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
| #include <iostream> using namespace std;
template<class T> class base;
class A1;
template<class TA2> class A2;
template<class TA3> class A3;
template<class TA4> class A4;
template<class T> void externprint2();
template<class T> T getvalue2(const base<T>& b);
template<class T> class base { private: T val; public: base(T value) :val(value) {} friend void externprint(); friend T getvalue(const base<T>& b); friend class A1; friend class A2<int>; friend void externprint2<T>(); friend T getvalue2<>(const base<T>& b); friend class A3<T>;
template<class T1> friend bool externprint3(T1 t); template<class TA2> friend class A4; }; base<double> bd(3.14); base<int> bi(5);
void externprint() { cout << sizeof(bi.val) << ","; cout << sizeof(bd.val) << endl; return; }
int getvalue(const base<int>& b) { cout << "int base:" << b.val << endl; return b.val; } double getvalue(const base<double>& b) { cout << "double base:" << b.val << endl; return b.val; }
template<class T> void externprint2() { if(bd.val) cout << sizeof(base<T>) << endl; return; }
template<class T> T getvalue2(const base<T>& b) { cout << typeid(base<T>).id() << " base:" << b.val << endl; return b.val; }
template<class T1> bool externprint3(T1 t) { if (t == bd.val)return true; else return false; }
class A1 { base<int> b1; base<double> b2; base<char> b3; base<string> b4; public: A1() :b1(3), b2(3.14), b3('a'), b4("bbb") {} void print() { cout << b1.val << endl; cout << b2.val << endl; cout << b3.val << endl; cout << b4.val << endl; cout << endl; } };
template<class TA2> class A2 { private: base<int> b1; base<double> b2; base<char> b3; base<string> b4; public: TA2 bb; A2() :b1(3), b2(3.14), b3('a'), b4("bbb") {} void print() { cout << b1.val << endl; cout << b2.val << endl; cout << b3.val << endl; cout << b4.val << endl; bb = b1.val; cout << bb << endl; cout << endl; } };
template<class TA3> class A3 { base<int> b1; base<double> b2; base<char> b3; base<string> b4; public: TA3 bb; A3() :b1(3), b2(3.14), b3('a'), b4("bbb") {} void print() { cout << b1.val << endl; cout << b2.val << endl; cout << b3.val << endl; cout << b4.val << endl; bb = b3.val; cout << bb << endl; cout << endl; } void print2() { cout << b1.val << endl; bb = b1.val; cout << bb << endl; cout << endl; } void print3() { cout << b3.val << endl; bb = b3.val; cout << bb << endl; cout << endl; } };
template<class TA4> class A4 { base<int> b1; base<double> b2; base<char> b3; base<string> b4; public: TA4 bb; A4() :b1(3), b2(3.14), b3('a'), b4("bbb") {} void print() { cout << b1.val << endl; cout << b2.val << endl; cout << b3.val << endl; cout << b4.val << endl; bb = b4.val; cout << bb << endl; cout << endl; } };
int main() { A1 a1; A2<int> a21; A2<double> a22; A3<int> a31; A3<char> a32; A4<string> a41; A4<char> a42; externprint(); externprint2<double>(); cout << externprint3(3) << endl; cout << externprint3(3.14) << endl; cout << endl; a1.print(); a21.print(); a31.print2(); a32.print3(); a41.print(); return 0; }
|
7. 类模版和static成员:
从类模版实例化的每个模版类有自己的类模版数据成员,该模版类的所有对象共享一个static数据成员。
每个模版类有自己的类模板的static数据成员副本,这之间不是直接共享的。
和非模版类的static数据成员一样,模版类的static数据成员也应该在文件范围定义和初始化。
static数据成员可以用类属参数对应的类型声明,在外部定义时无需赋值,但是需要在前面说明template和类属参数表,以对类模版的相关模版类进行定义,这些static成员在创建模版类时自动默认初始化(如int则初始化为0,等等)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include<iostream> using namespace std; template<class T> class A { protected: T val; static int totalcount; static T totalval; public:
A(T v) :val(v) { totalcount += 1; totalval += val; } static T gettotalval() { return totalval; } static int gettotalcount() { return totalcount; } T getval() { return val; } ~A() { totalcount -= 1; totalval -= val; } };
template<class T> T A<T>::totalval;
template<class T> int A<T>::totalcount=0; int main() { A<double> a1(5.5), a2(4.5), a3(3); A<int> a4(5), a5(4); cout << A<double>::gettotalcount() << endl; cout << A<double>::gettotalval() << endl; cout << A<int>::gettotalcount() << endl; cout << A<int>::gettotalval() << endl; return 0; }
|