副标题#e#
媒介
永远记着,编写代码的宗旨在于简朴明白,不要利用语言中的默默特性,耍小智慧,重要的是编写你领略的代码,领略你编写的代码,这样你大概会做的更好。
1998年,国际C++尺度正式通过,尺度化对C++最重要的孝敬是:对"强大的抽象观念"给于更有力的支持,以低落软件的巨大度,C++提供了二种成果强大的抽象要领:面向工具编程与泛型编程。面向工具编程各人必然很熟悉了,这里就不再颤抖了。提到泛型编程(Generic Programming),有的人大概还不太熟悉,可是提到STL,你就必然会有所耳闻了。STL(Standard Template Library,尺度模板库) 其实就是泛型编程的实现品,STL是由Alexander Stepanov(STL之父)、David R Musser和Meng Lee三位大家配合成长,于1994年被纳入C++尺度措施库。STL固然插手C++尺度库的时间相对较晚,但它却是C++尺度措施库中最具革命性的部门,同时也是C++尺度措施库中最重要的构成部门。由于新的C++尺度库中险些每一样对象都是由模板(Template)组成的,虽然,STL也不会破例。所以,在这里有须要先提要说明一下模板的有关观念。
模板观念
通过利用模板可以使措施具有更好的代码重用性。记着,模板是对源代码举办重用,而不是通过担任和组合重用工具代码,当用户利用模板时,参数由编译器来替换。模板由类模板和函数模板二部门构成,以所处理惩罚的数据范例的说明作为参数的类就叫类模板,而以所处理惩罚的数据范例的说明作为参数的函数叫做函数模板。模板参数可以由范例参数或非范例参数构成,范例参数可用class和typename要害字来指明,二者的意义沟通,都暗示后头的参数名代表一个潜在的内置或用户界说的范例,非范例参数由一个普通参数声明组成。下面是类模板和函数模板的简朴用法:
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);
#p#副标题#e#
泛型编程
泛型编程和面向工具编程差异,它并不要求你通过特另外间接层来挪用函数,它让你编写完全一般化并可反复利用的算法,其效率与针对某特定命据范例而设计的算法沟通。泛型编程的代表作品STL是一种高效、泛型、可交互操纵的软件组件。所谓泛型(Genericity),是指具有在多种数据范例上皆可操纵的含意,与模板有些相似。STL庞大,并且可以扩充,它包括许多计较机根基算法和数据布局,并且将算法与数据布局完全疏散,个中算法是泛型的,不与任何特定命据布局或工具范例系在一起。STL以迭代器(Iterators)和容器(Containers)为基本,是一种泛型算法(Generic Algorithms)库,容器的存在使这些算法有对象可以操纵。STL包括各类泛型算法(algorithms)、泛型指针(iterators)、泛型容器(containers)以及函数工具(function objects)。STL并非只是一些有用组件的荟萃,它是描写软件组件抽象需求条件的一个正规而有层次的架构。
迭代器(Iterators)是STL的焦点,它们是泛型指针,是一种指向其他工具(objects)的工具,迭代器可以或许遍历由工具所形成的区间(range)。迭代器让我们得以将容器(containers)与浸染其上的算法(algorithms)疏散,大大都的算法自身并不直接操纵于容器上,而是操纵于迭代器所形成的区间中。迭代器一般分为五种:Input Iterator、Output Iterator、Forward Iterator、Bidirections Iterator和Random Access Iterator。Input Iterator就象只从输入区间中读取数据一样,具有只读性,属于单向移动,如STL中的istream_iterator。Output Iterator恰好相反,只写出数据到输出区间中,具有只写性,属于单向移动,如STL中的ostream_iterator。Forward Iterator也属于单向移动,但差异之处是它同时具有数据读、写性。Bidirections Iterator如名称体现,支持双向移动,不单可以累加(++)取得下一个元素,并且可以递减(–)取前一个元素,支持读、写性。Random Access Iterator成果最强,除了以上各迭代器的成果外,还支持随机元素会见(p+=n),下标(p[n])、相减(p1-p2)及前后序次干系(p1<p2)等。Input Iterator和Output Iterator属于同等最弱的二种迭代器,Forward Iterator是前二者成果的强化(refinement),Bidirections Iterator又是Forward Iterator迭代器的强化,最后Random Access Iterator又是Bidirections Iterator迭代器的强化。如下简朴示例展示Input Iterator、Forward Iterator、Bidirections Iterator和Radom Access Iterator迭代器的成果(个中input_iterator_tag等带tag字符串为各差异迭代器的专属标识):
1、InputIterator
#p#分页标题#e#
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界说的其他所有函数工具都是这三种观念的强化。如下简朴示例展示几种形式的实现:
1、无参(Generator)形式
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
设计新思维
#p#分页标题#e#
将设计模式(design patterns)、泛型编程(generic programming)和面向工具编程(object-oriented programming)有机的团结起来,便形成了设计新思维。个中,设计模式是颠末提炼的精彩设计要领,对付许多环境下遇到的问题,它都是公道而可复用的办理方案;泛型编程是一种规范(paradigm),专注于将范例抽象化,形乐成能需求方面的一个风雅荟萃,并操作这些需求来实现算法,沟通的算法可以运用于遍及的范例会合,所谓泛型,就是具有在多种数据范例上皆可操纵的含意;最后同面象工具编程中的多态(polymorphism)和模板(templates)等技能相团结,便得到极高条理上的具有可复用性的泛型组件。泛型组件预先实现了设计模块,可以让用户指定范例和行为,从而形成公道的设计,主要特点是机动、通用和易用。
policies和policy类,是一种重要的类设计技能,所谓policy,是用来界说一个类或类模板的接口,该接口由下列之一或全部构成:内部范例界说、成员函数和成员变量。基于policy的类由很多小型类(称为policies)构成,每一个这样的小型类只认真纯真如行为或布局的某一方面。Policies机制由模板和多重担任构成,它们可以相互殽杂搭配,从而形成设计戎的多样性,通过plicy类,不单可以定制行为,也可以定制布局。
下面简朴举例说明泛化思维和面向工具思维在部门设计模式中的运用。
Singletons设计模式泛化实现 Singleton模式是一种担保一个工具(class)只有一个实体,并为它提供一个全局会见点。Singleton是一种颠末改造的全局变量,既在措施中只能有独一实体的范例,它的重点主要会合在发生和打点一个独立工具上,并且不答允发生另一个这样的工具。
先让我们看看一般的C++实现的根基手法,下面是实现源码:
// 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;
#p#分页标题#e#
如上所示,Singleton模式实现中只有一个public成员Instance()用来第一次利用时建设单一实例,当第二次利用时静态变量将已经被设定好,不会再次建设实例。还将默认结构函数、拷贝结构函数和赋值操纵符放在private中,目地是不让用户利用它们。别的,为制止实例意外消毁后再实例化环境,插手静态布尔变量destroy_来举办判定是否堕落,从而到达不变性。
从上面一般实现可以看出Singleton模式实现主要在于建设(Creation)方面和保留期(Lifetime)方面,既可以通过各类要领来建设Singleton。Creation一定能建设和摧毁工具,一定要开放这两个相应函数,将建设作为独立计策分分开来是必须的,这样你就可以建设多态工具了,所以泛化Singleton并不拥有Creator工具,它被放在CreationPolicy<T>类模板之中。生命期是指要遵循C++法则,后建设都先摧毁,认真措施生命期某一时刻摧毁Singleton工具。
下面是一个简朴的泛化Singleton模式的实现(不思量线程因素)
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()两函数是用来建设并摧毁详细工具的。
下面是上述泛化Singleton模式实现的利用:
1、应用一
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++中缔造可扩充设计的新要领,提供了从设计到代码的浅易过渡,辅佐我们编写清晰、机动、高度可复用的代码。
参考文献
C++ Primer(第三版) — 潘爱民等译
Effective C++(第二版) — 侯捷译
More Effective C++ — 侯捷译
Exceptional C++ — 卓小涛译
More Exceptional C++ — 於春光译
深度摸索C++工具模子 — 侯捷译
泛型编程与STL — 侯捷译
C++ STL措施员开拓指南 — 彭木根等箸
设计模式:可复用面向工具软件的元素 — 李英军等译
C++设计新思维 — 侯捷等译