c++模板(二)---------类模板
来源:互联网 发布:不喜欢知否的男主 编辑:程序博客网 时间:2024/06/05 02:47
二、类模板
1、定义类模板
示例,一个基于模板自定义的栈:
#ifndef STACK_H_#define STACK_H_/*一个基于模板自定义的栈*/template <class Type>class Stack{private: enum { MAX = 10};//一个常量用来辅助数组定义 Type items[MAX]; //内部数组存放着 type们 int top;public: Stack(); bool isempty(); bool isfull(); bool push(const Type & item); bool pop(Type & item); ~Stack();};template <class Type>Stack<Type>::Stack(){ top = 0;}template <class Type>bool Stack<Type>::isempty() { return top == 0;}template <class Type>bool Stack<Type>::isfull() { return top == MAX;}template <class Type>bool Stack<Type>::push(const Type & item) { if (top < MAX) { items[top++] = item; return true; } else { return false; }}template <class Type>bool Stack<Type>::pop(Type & item) { if (top > 0) { item = items[--top]; return true; } else { return false; }}template <class Type>Stack<Type>::~Stack(){}#endif // !STACK_H_
需注意:成员函数使用Stack< Type >进行限定,而不是Stack。
附上简单的测试代码:
#include "stdafx.h"#include <iostream>#include "Stack.h"#include "Stack.cpp"int main() { using namespace std; Stack<int> mStack; int i = 0; for (; ;i++) { if (mStack.isfull())break; mStack.push(i); } int result; for (; i > 0; i--) { mStack.pop(result); cout << "out: " << result << endl; } system("pause");}执行结果:out: 9out: 8out: 7out: 6out: 5out: 4out: 3out: 2out: 1out: 0请按任意键继续. . .
2、非类型参数
有模板头: template < classs T ,int n > 的话。关键字class (或与它等价的typename)指出了 T 为类型参数,int 指出了n的类型为int。这种参数(指定特殊的类型而不是用作泛型名)成为非类型(non-type)或表达式(expression)参数。
假设有下面的声明:
ArrayTP< double , 12 > eggweights。这将导致编译器定义名为ArrayTP< double,12>的类 ,并创建一个类型为ArrayTP< double ,12>的eggweight对象,定义类时,将使用double替换T,使用12替换n 。
表达式是有一些限制的,表达式参数可以是整型、枚举、引用或指针。
3、模板的多功能性
模板可以用作基类,也可以用作组件类,还可以用作其他模板的类型参数。
a、递归使用模板
示例:
ArrayTP< ArrayTP< int > > aas;
b、使用多个类型参数
示例:
template <class T1,class T2> class Test {private: T1 t1; T2 t2;public : ....};
c、默认类型模板参数
模板的另一项新特性是,可以为类型参数提供默认值;
template <class T1, class T2 = int> class Topo {...};
这样如果省略T2时,编译器就使用int .
注意:虽然可以为类模板类型参数提供默认值,但不能为函数模板提供默认值。然而可以为非类型参数提供默认值,这对于类模板和函数模板都很适合。
4、模板具体化
假设有类定义如下:
template <class T1, int n = int>class Test {private: T1 t1;public: ....};
A. 隐式实例化
Test< double, 30> test;
这也是最常用的实例化。
注意编译器在需要对象之前,不会生成类的隐式实例。
Test< double, 21> * pt; // 一个指针,还没有对象 pt = new Test< double, 21 >(); //有了一个对象
B. 显示实例化
template class Test< int, 100>; //生成 Test<int ,100> class ;
在这种情况下,虽然没有创建或提及类对象,编译器也将生成类声明(包括方法定义)。和隐式实例化一样,也将根据通用模板来生成具体化。
C. 显示具体化
template<> class Test <int, 100> { //显示具体化....}
D. 部分具体化
假设有类:
template <class T1,class T2>class Test2 { .....};
template <class T1> class Test2<T1, int> {...};
则上述声明将T2具体化为int ,但T1保持不变,如果指定所有的类型,则<>内为空。这将导致显示具体化。
如果有多个模板可供选择,编译器会使用具体化程度最高的模板。
5、成员模板
示例:
#ifndef BETA_H_#define BETA_H_#include <iostream>using namespace std;template <typename T>class beta{private: template < typename V > class hold { private : V val; public: hold(V v = 0) : val(v) {} void show() const { cout << val << endl; } V value() const { return val; } }; hold<T> q; hold<int> n;public: beta(T t, int i): q(t), n(i) {}; template <typename U > U blab(U u, T t) { return (n.value() + q.value()) * u / t; } void show() const { q.show(); n.show(); }};#endif // !BETA_H_
如果编译器接收模板成员在外面定义的话,也可以使用如下代码
beta.h
#ifndef BETA_H_#define BETA_H_#include <iostream>using namespace std;template <typename T>class beta{private: template < typename V > class hold; hold<T> q; hold<int> n;public: beta(T t, int i): q(t), n(i) {}; template <typename U > U blab(U u, T t); void show() const { q.show(); n.show(); }};#endif // !BETA_H_
beta.cpp
#include "stdafx.h"#include "beta.h"template<typename T >template <typename V>class beta<T>:: hold {private: V val;public: hold(V v = 0) : val(v) {} void show() const { cout << val << endl; } V value() const { return val; }};template <typename T>template <typename U >U beta<T>:: blab(U u, T t) { return (n.value() + q.value()) * u / t;}
因为模板是嵌套的,因此必须使用template< typename T> template< typename V >
而不能使用template< typename T ,typename V >
6、将模板用作参数
示例:
template < template <typename T > class Thing> class Crab { private: Thing< int > s1; Thing < double > s2 ; ... public : .... };
其中 template < typename T > class 是类型,Thing 是参数。Thing必须一个模板类。假如实例化时使用 Crab< Stack > nebula; 那么 Crab中的那2个成员变量将会被替换为 Stack< int > s1 和 Stack< double > s2 ;
还可以混合使用模板参数与常规参数例如:
template < template <typename T > class Thing ,typename U, typename V> class Crab { private : Thing<U > s1; Thing<V> s2; };
7、模板类和友元
模板的友元分3类
- 非模板友元
- 约束模板友元
非约束模板友元
A、非模板友元:
#include<iostream>using namespace std;template <class T>class HasFriend{private : T item; static int ct;public: friend void counts(); friend void reports(HasFriend<T> &); HasFriend(const T & i) item(i) {ct++}; ~HasFriend() {ct --};};template <typename T>int HasFriend<T>::ct = 0;//非模板友元void counts(){}//非模板友元 具体化接收 HasFriend<int> 参数void reports(HasFriend<int > & a) {}//非模板友元 具体化接收 HasFriend<double> 参数void reports(HasFriend<double> & b) {}
B、约束模板友元
#include<iostream>using namespace std;template <typename T > void counts();template <typename T > void report(T &);template <typename T>class HasFriend{private : T item; static int ct;public: friend void counts<T>(); /*这里可以使用<> 因为可以从形参中推断出类型 */ friend void report<>(HasFriend<T> &); HasFriend(const T & i) item(i) {ct++}; ~HasFriend() {ct --};};template <typename T>int HasFriend<T>::ct = 0;template <typename T >void counts(){}template <typename T>void report(T & hf){}
使用约束模板友元主要分三步
1.在类定义之前声明每个模板函数
2.在类中再次将模板函数声明为友元,这些语句根据模板参数的类型声明具体化
3.定义函数
C、非约束模板友元
通过类内部声明模板,可以创建非约束友元函数。
template <typename T >class ManyFriend { .... template <typename C, typename D> friend void show(C &, D &);};
附上测试代码:
#include<iostream>using namespace std;template <typename T > void counts();template <typename T > void report(T &);template <typename T>class HasFriend{private : T item; static int ct;public: friend void counts<T>(); /*这里可以使用<> 因为可以从形参中推断出类型 */ friend void report<>(T &); template <typename C, typename D> friend void show(C & , D &); HasFriend(const T & i) :item(i) { ct++; } ~HasFriend(){ ct--; }};template <typename T>int HasFriend<T>::ct = 0;template <typename T >void counts(){}template <typename T>void report(T & hf){}template <typename C, typename D> void show(C & c, D & d) { cout << "c : " << c << " d: " << d << endl;}
#include "stdafx.h"#include <iostream>#include "HasFriend.h"int main() { HasFriend<int> h(); int a = 10; double b = 20.1; show(a, b); system("pause");}执行结果:c : 10 d: 20.1请按任意键继续. . .
8、模板别名
template < typename T >
using arrtype = std::array< T ,12> ;
这将arrtype定义为了一个模板别名,可以使用它来指定类型。如:
arrtype< double > gallons; //等价于 std::array< double ,12>
c++11 还允许将语法using= 用于非模板。用于非模板时,这种语法与常规语法typedef等价。
typedef const char * pc1 ;
using pc2 = const char * ;
这2种等价。
- 类模板(二)
- c++模板(二)---------类模板
- 类模板与模板类(C++)
- Linux C/C++ 模板:类模板(主模板)
- C++模板(二)-类模板
- C++STL模板容器(二)
- linux c 编程模板总结(二)
- 【c++】模板和模板类
- c++类模板(二)
- 【c/c++】类模板
- 【C/C++】模板类
- C/C++:函数模板与类模板
- [C/C++]模板函数与模板类
- Argument 模板(二)
- C++模板(二)
- C++模板(二)
- 模板(二)
- C++模板(二)
- Git使用教程
- Android下event事件深度解析
- 最近5年133个Java面试问题列表
- CodeForces - 673B Problems for Round (模拟)水
- MYSQL必知必会读书笔记 第二十六章 管理事务处理
- c++模板(二)---------类模板
- java的IO操作
- 轻松制作GIF动画!教你玩转PS时间轴之进阶技巧篇
- memcache安装及使用详解
- [Leetcode] 13. Roman to Integer
- python里面的函数
- sqoop mysql to hbase java api 1.4.5
- 198.[Leetcode]House Robber
- 控制seekBar的进度颜色