缺省模板参数
- template < typename T, typename CONT = deque< T > >
#ifndef _STACK_H_
#define _STACK_H_
#include <exception>
#include <deque>
using namespace std;
template <typename T, typename CONT = deque<T> >
class Stack
{
public:
Stack(); //防止隐式转换
~Stack();
void Push(const T& elem);
void Pop();
T& Top();
const T& Top() const;
bool Empty() const;
private:
CONT c_;
int top_;
};
template <typename T, typename CONT = deque<T> >
Stack<T, CONT>::Stack() : c_()
{
}
template <typename T, typename CONT = deque<T> >
Stack<T, CONT>::~Stack()
{
}
template <typename T, typename CONT = deque<T> >
void Stack<T, CONT>::Push(const T& elem)
{
c_.push_back(elem);
}
template <typename T, typename CONT = deque<T> >
void Stack<T, CONT>::Pop()
{
if (c_.empty())
throw out_of_range("Stack::Pop() Stack empty");
c_.pop_back();
}
template <typename T, typename CONT = deque<T> >
T& Stack<T, CONT>::Top()
{
if (c_.empty())
throw out_of_range("Stack::Pop() Stack empty");
return c_.back();
}
template <typename T, typename CONT = deque<T> >
const T& Stack<T, CONT>::Top() const
{
if (c_.empty())
throw out_of_range("Stack::Pop() Stack empty");
return c_.back();
}
template <typename T, typename CONT = deque<T> >
bool Stack<T, CONT>::Empty() const
{
return c_.empty();
}
#endif // _STACK_H_
#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;
}
成员模板
- 为什么要有成员模板
template <typename T>
class Myclass
{
public:
T value;
private:
void Assign(const Myclass<T>& x)
{
value = x.value;
}
};
//main函数中有如下语句
Myclass<double> d;
Myclass<int> i;
d.Assign(d); //OK
d.Assign(i); //Error
//类型不一样,无法传递
//这是我们就需要让成员函数也是模板
#include<iostream>
using namespace std;
template <typename T>
class Myclass
{
public:
Myclass() //默认构造函数
{
}
template <typename X> //模板构造函数
Myclass(const Myclass<X>& x) : value(x.GetValue())
{
}
template <typename X> //模板函数
void Assign(const Myclass<X>& x)
{
value = x.GetValue(); //当X和T不是同一种类型的时候,无法访问私有成员,必须提供接口函数
}
T GetValue() const
{
return value;
}
private:
T value;
};
//main函数中有如下语句
int main(void)
{
Myclass<double> d;
Myclass<int> i;
d.Assign(d); //OK
d.Assign(i); //OK
Myclass<double> d1(i); //必须要有模板构造函数
return 0;
}
typename关键字
#include<iostream>
using namespace std;
template <typename T>
class Myclass
{
private:
typename T::SubType* ptr_; //如果此处没有typename,此处会将SubType解析为“T类型里的一个静态数据成员乘以ptr_"
};
class Test
{
public:
typedef int SubType;
};
int main(void)
{
Myclass<Test> mc;
return 0;
}
派生类和模板区别
为了运行的效率,类模板是相互独立的,即独立设计,没有使用继承的思想。对类模板的扩展是采用适配器(adapter)来完成的。通用性是模板库的设计出发点之一,这是由泛型算法和函数对象等手段达到的。
派生的目标之一也是代码的复用和程序的通用性,最典型的就是MFC,派生类的优点是可以由简到烦,逐步深入,程序编制过程中可以充分利用前面的工作,一步步完成一个复杂的任务。
模板追求的是运行效率,而派生类追求的是编程的效率。
面向对象与泛型编程
面向对象与泛型都依赖于某个形式的多态
面向对象
- 动态多态 ——虚函数
- 静态多态 ——模板
面向对象中的多态在运行时应用存在继承关系。我们编写使用 这些类的代码,忽略使用基类与派生类之间的类型差异。只要使用基类指针或者引用,基类类型对象、派生类类型对象就可以共享相同的代码。
在泛型编程中,我们所编写的类和函数能够多态的用于编译时不相关的类型。一个类或一个函数可以用来操作多种类型的对象。