作者:徐景周
前言
永远记住,编写代码的宗旨在于简单明了,不要使用语言中的冷僻特性,耍小聪明,重要的是编写你理解的代码,理解你编写的代码,这样你可能会做的更好。
template<class T1, int Size>
class Queue // 类模板,其中T1为类型参数,Size为非类型参数
{
public:
explicit Queue():size_(Size){}; // 显式构造,避免隐式转换
……
template<class T2> void assign(T2 first,T2 last); // 内嵌函数模板
private:
T* temp_;
int size_;
}
// 类模板中内嵌函数模板Compare的外围实现(如在Queue类外实现)
template<class T1,int Size> template<class T2>
void Queue<T1,Size>::assign (T2 first,T2 last) {};
// 模板的使用方法
int ia[4] = {0,1,2,3};
Queue<int, sizeof(ia)/sizeof(int)> qi;
qi.assign(ai,ai+4);
泛型编程 template<class InputIterator, class Distance>
void advance(InputIterator& i, Distance n, input_iterator_tag)
{
for(; n>0; --n,++i){} // InputIterator具有++性
}
2、ForwardIterator
template<class ForwardIterator, class Distance>
void advance(ForwardIterator& i, Distance n,forward_iterator_tag)
{
advance(i, n, input_iterator_tag());
}
3、BidirectionalIterator
template<class BidirectionalIterator, class Distance>
void advance(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag)
{
if(n>=0) // 具有++、--性
for(; n>0; --n,++i){}
else
for(; n>0; ++n,--i){}
}
4、RandomAccessIterator
template<class RandomAccessIterator, class Distance>
void advance(RandomAccessIterator& i, Distance n, random_access_iterator_tag)
{
i += n; // 具有++、--、+=等性
}
函数对象(Function object)也称仿函数(Functor),是一种能以一般函数调用语法来调用的对象,函数指针(Function pointer)是一种函数对象,所有具有operator()操作符重载的成员函数也是函数对象。函数对象一般分为无参函数(Generator),单参函数(Unary Function)和双参函数(Binary Function)三种形式,它们分别能以f()、f(x)和f(x,y)的形式被调用,STL定义的其他所有函数对象都是这三种概念的强化。如下简单示例展示几种形式的实现: struct counter
{
typedef int result_type;
counter(result_type init=0):n(init){}
result_type operator() { return n++;}
result_type n;
}
2、单参(Unary Function)形式
template<class Number> struct even // 函数对象even,找出第一个偶数
{
bool operator()(Number x) const {return (x&1) == 0;}
}
// 使用算法find_if在区间A到A+N中找到满足函数对象even的元素
int A[] = {1,0,3,4};
const int N=sizeof(A)/sizeof(int);
find_if(A,A+N, even<int>());
3、双参(Binary Function)形式
struct ltstr
{
bool operator()(const char* s1, const char* s2) const
{ return strcmp(s1<s2) < 0;}
};
// 使用函数对象ltstr,输出set容器中A和B的并集
const int N=3
const char* a[N] = {"xjz","xzh","gh"};
const char* b[N]= {"jzx","zhx","abc"};
set<const char*,ltstr> A(a,a+N);
set<const char*,ltstr> B(b,b+N);
set_union(A.begin(),A.end(),B.begin(),B.end(),
ostream_iterator<const char*>(cout," "), ltstr());
容器(container)是一种对象(object),可以包含并管理其它的对象,并提供迭代器(iterators)用以定址其所包含之元素。根据迭代器种类的不同,容器也分为几中,以Input Iterator为迭代器的一般container,以Forward Iterator为迭代器的Forward Container,以Bidirectional Iterator 为迭代器的Reversible Container,以Random Access Iterator为迭代器的Random Access Container。STL定义二种大小可变的容器:序列式容器(Sequence Container)和关联式容器(Associative Container)序列式容器包括vector、list和deque,关联式容器包括set、map、multiset和multimap。以下示例简单说明部分容器的使用:
1、vector使用
// 将A中以元素5为分割点,分别排序,使排序后5后面的元素都大于5之前的元素(后区间不排序),
// 然后输出
int main()
{
int A[] = {7,2,6,4,5,8,9,3,1};
const int N=sizeof(A)/sizeof(int);
vector<int> V(A,A+N);
partial_sort(V,V+5,V+N);
copy(V,V+N,ostream_iterator<int>(cout," "));
cout << endl;
}
输出可能是:1 2 3 4 5 8 9 7 6
2、list使用
// 产生一空list,插入元素后排序,然后输出
int main()
{
list<int> L1;
L1.push_back(0);
L1.push_front(1);
L1.insert(++L1.begin,3);
L1.sort();
copy(L1.begin(),L1.end(),ostream_iterator<int>(cout," "));
}
输出:0 1 3
3、deque使用
int main()
{
deque<int> Q;
Q.push_back(3);
Q.push_front(1);
Q.insert(Q.begin()+1,2);
Copy(Q.begin(),Q.end(),ostream_iterator<int>(cout," "));
}
输出:1 2 3
4、map使用
int main()
{
map<string,int> M;
M.insert(make_pair("A",11);
pair<map<string,int>::iterator, bool> p = M.insert(make_pair("C",5));
if(p.second)
cout << p.first->second<<endl;
}
输出:5
5、multiset使用
int main()
{
const int N = 5;
int a[N] = {4,1,1,3,5};
multiset<int> A(a,a+N);
copy(A.begin(),A.end(),ostream_iterator<int>(cout," "));
}
输出:1 1 3 4 5
设计新思维 // Singleton.h文件中
class Singleton
{
public:
static Singleton& Instance()
{
if(!pInstance_){
if(destroyed_){ // 引用是否已经失效
OnDeadReference();
}
else {
Create(); // 第一次时创建实例
}
}
return *pInstance_;
}
private:
Singleton(); // 禁止默认构造
Singleton(const Singleton&); // 禁止拷贝构造
Singleton& operator= (const Singleton&); // 禁止赋值操作
static void Create() // 传加创建的实例引用
{
static Singleton theInstance;
pInstance_ = &theInstance;
}
static void OnDeadReference()
{
throw std::runtime_error(" 实例被不正当消毁");
}
virtual ~Singleton()
{
pInstance- = 0;
destroyed_ = true;
}
static Singleton *pInstance_;
static bool destroyed_;
}
// Singleton.cpp中静态成员变量初始化
Singleton* Singleton::pInstance_ = 0;
Bool Singleton::destroyed_ = false;
如上所示,Singleton模式实现中只有一个public成员Instance()用来第一次使用时创建单一实例,当第二次使用时静态变量将已经被设定好,不会再次创建实例。还将默认构造函数、拷贝构造函数和赋值操作符放在private中,目地是不让用户使用它们。另外,为避免实例意外消毁后再实例化情况,加入静态布尔变量destroy_来进行判断是否出错,从而达到稳定性。 template
<
class T,
template<class> calss CreationPolicy = CreateUsingNew,
template<class> class LifetimePolicy=DefaultLifetime,
>
classs SingletonHolder
{
public:
static T& Instance()
{
if(!pInstance_)
{
if(destroyed_)
{
LifetimePolicy<T>::OnDeadReference();
destroyed_ = false;
}
pInstance_ = CreationPolicy<T>::Create();
LifetimePolicy<T>::SchedultCall(&DestorySingleton);
}
return *pInstance_;
}
private:
static void DestroySinleton()
{
assert(!destroyed_);
CreationPlicy<T>::Destroy(pInstance_);
pInstance_ = 0;
destroyed_ = true;
}
SingletonHolder();
SingletonHolder (const SingletonHolder &);
SingletonHolder & operator= (const SingletonHolder &);
Static T* pInstance_;
Static bool destroyed_;
};
Instance()是SingletonHolder开放的唯一一个public函数,它在CreationPolicy、LifetimePolicy中打造了一层外壳。其中模板参数类型T,接收类名,既需要进行Singleton的类。模板参数内的类模板缺省参数CreateUsingNew是指通过new操作符和默认构造函数来产生对象,DefaultLifetime是通过C++规则来管理生命期。LifetimePolicy<T>中有二个成员函数,ScheduleDestrution()函数接受一个函数指针,指向析构操作的实际执行函数,如上面DestorySingleton析构函数;OnDeadReference()函数同上面一般C++中同名函数相同,是负责发现失效实例来抛出异常的。CreationPlicy<T>中的Create()和Destroy()两函数是用来创建并摧毁具体对象的。 class A{};
typedef SingletonHolder<A, CreateUsingNew> SingleA;
2、应用二
class A{};
class Derived : public A {};
template<class T> struct MyCreator : public CreateUsingNew<T>
{
static T* Create()
{
return new Derived;
}
static void Destroy(T* pInstance)
{
delete pInstance;
}
}
typedef SingletonHolder<A,MyCreator> SingleA;
通过上面示例可以看出, SingletonHolder采用基于plicy设计实现,它将Singleton对象分解为数个policies,模板参数类中CreationPolicy和LifetimePolicy相当于二个policies封装体。利用它们可以协助制作出使用者自定义的Singleton对象,同时还预留了调整和扩展的空间。由此而得,泛型组件(generic components),是一种可复用的设计模板,结合了模板和模式,是C++中创造可扩充设计的新方法,提供了从设计到代码的简易过渡,帮助我们编写清晰、灵活、高度可复用的代码。