缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename
一、缺省模板参数
回顾前面的文章,都是自己管理stack的内存,无论是链栈还是数组栈,能否借助标准模板容器管理呢?答案是肯定的,只需要多传一个模板参数即可,而且模板参数还可以是缺省的,如下:
template <typename T, typename CONT = std::deque<T> >
class Stack
{
…
private:
CONT c_;
};
如果没有传第二个参数,默认为deque 双端队列,当然我们也可以传递std::vector<T>
下面程序借助标准模板容器管理内存来实现stack模板类:
Stack.h:
C++ Code
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 |
#ifndef _STACK_H_ #define _STACK_H_ #include <exception> #include <deque> using namespace std; template <typename T, typename CONT = deque<T> > class Stack { public: Stack() : c_() { } ~Stack() { } void Push(const T &elem) { c_.push_back(elem); } void Pop() { c_.pop_back(); } T &Top() { return c_.back(); } const T &Top() const { return c_.back(); } bool Empty() const { return c_.empty(); } private: CONT c_; }; #endif // _STACK_H_ |
main.cpp:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include "Stack.h" #include <iostream> #include <vector> using namespace std; int main(void) { /*Stack<int> s;*/ Stack<int, vector<int> > s; s.Push(1); s.Push(2); s.Push(3); while (!s.Empty()) { cout << s.Top() << endl; s.Pop(); } return 0; } |
输出为 3 2 1
即如果没有传递第二个参数,堆栈和压栈等操作直接调用deque<int> 的成员函数,也由deque<int> 管理内存。
如程序中传递vector<int> ,则由vector<int> 成员函数处理。
二、成员模板
来看下面的例子:
C++ Code
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 |
#include <iostream> using namespace std; template <typename T> class MyClass { private: T value; public: void Assign(const MyClass<T> &x) { value = x.value; } }; int main(void) { MyClass<double> d; MyClass<int> i; d.Assign(d); // OK d.Assign(i); // Error return 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 42 |
#include <iostream> using namespace std; template <typename T> class MyClass { private: T value; public: MyClass() {} template <class X> MyClass(const MyClass<X> &x) : value(x.GetValue()) { } template <class X> void Assign(const MyClass<X> &x) { value = x.GetValue(); } T GetValue() const { return value; } }; int main(void) { MyClass<double> d; MyClass<int> i; d.Assign(d); // OK d.Assign(i); // OK MyClass<double> d2(i); return 0; } |
auto_ptr<X> x;
auto_ptr<Y> y;
x = y;
三、typename 关键字
看下面的例子:
C++ Code
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 |
#include <iostream> using namespace std; template <typename T> class MyClass { private: typename T::SubType *ptr_; }; class Test { public: typedef int SubType; }; int main(void) { MyClass<Test> mc; return 0; } |
typename T::SubType *ptr_; 如果前面没有typename 修饰,则SubType会被认为是T类型内部的静态数据成员,推导下去,* 就不再认为是指针,而被
认为是乘号,编译的时候就出错了。加上修饰,就知道SubType 是T 内部的自定义类型,ptr是指向这种类型的指针,编译通过。
在vector 的源码中也可以发现下面的一些片段:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
template<> class _CRTIMP2_PURE allocator<void> { // generic allocator for type void public: template<class _Other> struct rebind { // convert an allocator<void> to an allocator <_Other> typedef allocator<_Other> other; }; .... } typedef typename _Alloc::template rebind<_Ty>::other _Alty; |
最后一行是类型定义,由于要解释_Alloc 类型需要引用的代码片段比较多,就姑且认为是allocator<int> 类型,可以看到 rebind<_Ty>
是成员模板类,other是成员模板类中自定义类型,_Ty 可以认为是int , 那么other 类型也就是allocator<int>, 也就是说_Alty 是类型
allocator<int> 。
此外还可以看到 :
template<class _Ty> class allocator {
templateclassvoid> { };
};
也就是说allocator<void> 是allocator 模板类的特化。
四、派生类与模板、面向对象与泛型编程
(一)、派生类与模板
1、为了运行的效率,类模板是相互独立的,即独立设计,没有使用继承的思想。对类模板的扩展是采用适配器(adapter)来完成的。通用性是模板库的设计出发点之一,这是由泛型算法(algorithm)和函数对象(functor)等手段达到的。
2、派生的目标之一也是代码的复用和程序的通用性,最典型的就是MFC,派生类的优点是可以由简到繁,逐步深入,程序编制过程中可以充分利用前面的工作,一步步完成一个复杂的任务。
3、模板追求的是运行效率,而派生追求的是编程的效率。
(二)、面向对象与泛型编程
1、面向对象与泛型都依赖于某个形式的多态
面向对象
动态多态(虚函数)
泛型
静态多态(模板类,模板函数)
2、面向对象中的多态在运行时应用存在继承关系。我们编写使用这些类的代码,忽略基类与派生类之间的类型差异。只要使用基类指针或者引用,基类类型对象、派生类类型对象就可以共享相同的代码。
3、在泛型编程中,我们所编写的类和函数能够多态地用于编译时不相关的类型。一个类或一个函数可以用来操纵多种类型的对象。
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范
- 从零开始学C++之模板(三):缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename
- 从零开始学C++之模板(三):缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename
- 从零开始学C++之模板(三):缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename
- 从零开始学C++之模板(三):缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename
- 用模板template<typename T>实现int double等类型转string
- 用模板template<typename T>实现int double等类型转string
- 用模板template<typename T>实现int double等类型转string
- 用模板template<typename T>实现int double等类型转string
- 用模板template<typename T>实现int double等类型转string
- 模板参数---实现容器适配器
- C++primer学习:类模板(2)类模板:模板参数,成员模板和控制实例化
- MS SQL Server 2008 新特性 - User-Defined Table Type 实现将.NET DataTable作为参数传入数据库
- JAVA 应用 V - 方法的可变参数。 format : typeName... parameters
- 使用两个Stack类(JDK容器类库中的Stack类)实现一个队列类MyQueue,提供队列的入队列和出队列操作:enQueue和deQueue
- <转载>模板声明中template <typename T>和template <class T>
- c++ template笔记(3)非类型模板参数nontype template parameters
- Gson通过借助TypeToken获取泛型参数的类型的方法(转)
- 创建一个直角三角形类(regular triangle)RTriangle类,实现下列接口IShape。两条直角边长作为RTriangle类的私有成员,类中包含参数为直角边的构造方法。
- C++模板编程->成员函数指针模板参数