现在的位置: 首页 > 综合 > 正文

Modern C++ Design 笔记 第一章 Policy-Based Class Design

2013年09月07日 ⁄ 综合 ⁄ 共 2955字 ⁄ 字号 评论关闭

Chapter 1, Policy-Based Class Design

如果说自己的知识领域是一个圆的话, 那么随着你的知识越来越多,
周长也就越长。换言之,和你不明白的知识交集越大,也可以说自己越发觉得无知。这就是翻了几页这本《Modern C++
Design》之后的感受。好像给自己打开了一个新的空间, 原来C++还可以这么写:)。这样的惊喜从第一张Policy-Based Class
Design就开始了。


谓Policy-based design, 有好事者在Wiki上给出的定义:Policy-based design, also known
as policy-based class design or policy-based programming, is a computer
programming paradigm based on an idiom for C++ known as policies. It
has been described as a compile-time variant of the strategy pattern,
and has connections with C++ template metaprogramming. It was first
popularized by Andrei Alexandrescu with his 2001 book Modern C++ Design
and his column Generic in the C/C++ Users
Journal.其实Wiki上这个定义简直和没说一样,一种编程方式,strategy模式的变种。用我们自己的大白话来说就是首先Policy
class定义了一些接口或者模板(这个有点像Strategy里面的那些个策略),然后具体模板类继承了这些policy
class,从而可以有选择性的拼装和己实例化自己想要的新类型,这样做避免了多重继承产生种种诸如类型,拷贝状态切换的问题。

还是看一个例子吧
template<
typename output_policy,
typename language_policy
>
class HelloWorld
: public output_policy,
public language_policy
{
using output_policy::Print;
using language_policy::Message;
public:
//behaviour method
void Run()
{
//two policy methods
Print( Message() );
}
};

#include

class HelloWorld_OutputPolicy_WriteToCout
{
protected:

template< typename message_type >
void Print( message_type message )
{
std::cout << message << std::endl;
}
};

#include

class HelloWorld_LanguagePolicy_English
{
protected:
std::string Message()
{
return "Hello, World!";
}
};

class HelloWorld_LanguagePolicy_German{
protected:
std::string Message()
{
return "Hallo Welt!";
}
};

int main()
{
/* example 1 */

typedef
HelloWorld<
HelloWorld_OutputPolicy_WriteToCout,
HelloWorld_LanguagePolicy_English
>
my_hello_world_type;

my_hello_world_type hello_world;
hello_world.Run(); //returns Hello World!

/* example 2
* does the same but uses another policy, the language has changed
*/

typedef
HelloWorld<
HelloWorld_OutputPolicy_WriteToCout,
HelloWorld_LanguagePolicy_German
>
my_other_hello_world_type;

my_other_hello_world_type hello_world2;
hello_world2.Run(); //returns Hallo Welt!
}


明显HelloWorld_OutputPolicy_WriteToCout和HelloWorld_LanguagePolicy_German以及
HelloWorld_LanguagePolicy_English就是三个policy
class,以愚之一二浅见以为,至少没有显示的生成一堆新的Class(比如不需要自己重新定义一堆
HelloWorldOuputEnglish,HelloWorldOuputGerman这样类似的新的类,当然实际上实例化的时候编译器还是做了这
个事情,只是这样的事情不需要你手动去做了,也不会有一堆的你需要维护的积木了! )
所以原则上很多动态的Strategy的应用其实交给policy class做是个不错的选择,policy
class还有一个优点在于可以在编译期间马上找到错误,要知道syntax valid but semantic error is more
sux than invalid syntax,一个好的libraray的实现就要尽量的避免这样的semantic error的存在。
现在我们开始来做一些改动,在HelloWorld_LanguagePolicy_English中添加一个接口
std::string Message2()
{
return "2 Hello, World!";
}
同时在helloworld中也添加一个接口
void Run2()
{
Print (Message2());
}

后在main函数中如果我们添加hello_world.Run2();语句的时候没问题。但是加上hello_world2.Run2();的时候编译
器抱怨说error C3861: 'Message2': identifier not found。
很明显HelloWorld_LanguagePolicy_German是不具备这样的接口的。所以用到policy
class的时候编译器可以帮助你做掉一点类型的检查,而不是让你在运行期间用那个号称很费时的RTTI知道自己的确切类型以后在做判断是否支持特定的类
型,这样就比较经济的避免运行期的类型检查。
如果我们更仔细的看这些policy
class中间用到的限制符的话我们可以发现,居然是protected.这个不是偶然的,我们从开始写C++老师就教导我们基类要有虚析构函数,不然的
话不能很好的析构。可是在这里我们不推荐虚析构这样的昂贵的方法。只要我们把这样policy class的析构函数设置成protected,
那么用户就没有办法单独实例化这些policy
class了,只有我们这样的Design可以很无缝的调用到他们的析构函数从而正确的销毁用过的资源。好像也是很有想法的。
今天就写到这里吧,慢慢来,悠着点。。。

抱歉!评论已关闭.