//1.模板定义以关键字template开始,后跟一个模板参数列表,此列表不能为空。编译器用推断出的模板参数来实例化一个特定版本的函数。类型参数前必须使用class或者typename(推荐使用typename)。 template <typename T> bool comp(T t0, T t1){return t0 > t1;} //2.除了定义类型参数外,还可以在模板中定义非类型参数。一个非类型参数表示一个值(必须是常量表达式,实际使用过程中,最好只使用整形,而不要使用其他类型)而非一个类型,通过特定的类型名而非typename来指定非类型参数。 template<int M> inline int fun(int (&p)[M]){return sizeof p;} //注意inline的位置 int a[10] = {}; int v = fun(a); //v = 40 //3.当编译器遇到一个模板定义时,它并不生成代码。只有当我们实例化出模板的一个特定版本时,编译器才会生成代码。这一特性影响了我们如何组织代码以及错误何时被检测到。 // 与模板代码不同,模板的头文件通常既包含声明,也包含定义。 //4.当调用一个函数模板的时候,编译器通常用函数实参为我们推断模板实参。 // 与函数模板的不同之处是,编译器不能为类模板推断模板参数类型,为了使用类模板,必须在模板名后的尖括号中提供额外信息,用来代替模板参数的模板实参列表(函数模板也能这么做)。 // 由以上可知,类模板的名字不是一个类型名,类模板用来实例化类型,而一个实例化的类型总是包含模板参数的。 // 因为类模板的名字不是类型名,而类模板名字加上尖括号以及显示模板实参才是一个类型名,所以在模板类外定义模板类的成员函数的时候必须以关键字template开始,后接类模板参数列表。 template<typename T> class CA { public: CA(){} public: T GetValue(); void SetValue(T t){value = t;} private: T value; }; template<typename T> T CA<T>::GetValue() {return value;} CA<int> A; A.SetValue(10); int value = A.GetValue(); //value = 10 //5.默认情况下,一个类模板的成员函数只有当程序用到它的时候才进行实例化。如果一个类模板的成员函数没有被用到,则此成员函数将不被实例化。 // 上述特性使得:即使某种类型不能完全符合模板的要求,我们仍能使用该类型实例化类。 //6.当我们使用一个类模板类型时必须提供模板实参,但这个规则有一个例外:在类模板自己的作用域中,我们可以直接使用模板名,而不提供实参。 //7.模板和友员 // 模板类与模板友元函数: // A.类为模板,友元函数也是模板,且使用的模板参数一致。 则此友元函数仅对相同模板参数的类实例具有特殊访问权限。 // B.类为模板,友元函数不是模板(使用指定模板实参类型的类实例)。 则友元函数只对指定类型的模板参数的类实例具有特殊访问权限。 // C.类为模板,友元函数也是模板,且使用的模板类型参数不一致。 则此友元函数对所有类实例都具有特殊访问权限。 // D.类不是模板,友元函数是模板。 则所有模板类型的友元函数都是对此类具有特殊访问权限。 // 模板类有模板类的友元关系(在A类中声明B类为其友元类) // a.A类为模板, B类是模板,且A类和B类使用的模板参数一致。 则此B类仅对相同模板参数的A类实例具有特殊访问权限。 // b.A类是模板, B类是模板,且A类和B类使用的模板参数不一致。 则所有B类的实例都对A类具有特殊访问权限 // c.A类是模板, B类不是模板。 则B类对所有A类的实例均具有特殊访问权限 // d.A类不是模板,B类是模板,且B类使用了指定模板实参类型。 则只有指定类型的B类实例才对A类具有特殊访问权限 // e.A类不是模板,B类是模板,且B类没有使用固定的模板类型。 则所有B类的实例都对A类具有特殊访问权限 template<typename T> class CMyTest { private: T value; public: T GetValue() {return value;} /*A结论*/friend void SetVlaue_10(CMyTest<T>& MyTest) {MyTest.value = 10;} /*结论B*/friend void SetValue_20(CMyTest<int> &MyTest);//注意点:此类型的友员函数不能定义在类的内部,否则会造成重定义 /*结论C*/template<typename X> friend void SetValue(CMyTest/*<T> 这里的<T>可加可不加*/ &temMyTest, X value) {temMyTest.value = value;} }; void SetValue_20(CMyTest<int> &MyTest) {MyTest.value = 20;} //前向声明 template<typename T>class CMyTest2; class CMyTest1 { public: void PrintfValueInt() {printf("%d\n", valueInt);} private: int valueInt; /*结论d*/friend class CMyTest2<CMyTest1>; /*结论e*/template<typename T> friend class CMyTest3; //注意这里的friend的位置 }; template<typename T> class CMyTest2 { public: void SetCMyTest1ValueInt_1000(T& a) {a.valueInt = 1000;} /*结论a*/friend class CMyTest3<T>; private: int value; }; template<typename T> class CMyTest3 { public: void SetCMyTest1ValueInt_3000(CMyTest1& a) {a.valueInt = 3000;} void SetValue_10(CMyTest2<T>& temMyTest) {temMyTest.value = 10;} private: T value; /*结论c*/friend class CMyTest4; }; class CMyTest4 { public: template<typename T>void SetValue(CMyTest3<T>& temTest, T value) {temTest.value = value;} /*结论D*/template<int X> friend void SetValue(CMyTest4 &MyTest) {MyTest.value = X;} private: int value; }; template<typename T> class CA { template<typename X> friend class CB; private: int value; }; template<typename X> class CB { template<typename T> /*结论b*/void Fun(CA<T> a) {a.value = 10;} }; //8.可以将模板类型参数声明为友员,即使使用内置类型也不会出错。 template<typename T> class CA { friend T; public: void SetValue(T v){value = v;} private: T value; }; class CB { public: CB(){} CB(int v) : value(v){} public: void Fun(CA<CB>); public: int value; }; void CB::Fun(CA<CB> a) {printf("%d\n", a.value.value);} CB b; CA<CB> a; a.SetValue(10); b.Fun(a); //输出10
时间: 2024-11-16 07:04:01