读书人

强大的C++挤出最后一滴水分解决方

发布时间: 2012-02-23 22:01:35 作者: rapoo

强大的C++——挤出最后一滴水分
挤出最后一滴水分
接着“千人一面”一贴,我们来看看局部特化的作用。
假设我们又多了一个类。这个类帮助我们从IC卡中读取xml流。(现在IC卡便宜了,容量也大了,允许我们用这种“奢侈”的方式存储数据了。:)):
class XmlFromIC
{
public:
bool Connect(const string& password);
bool Load(const string& session);
xmldoc GetXml();

};
没关系,我们再做一个Adatper <> 的特化就行了:
template <>
class Adapter <XmlFromIC>
{
public:
Adapter(T& obj)
: _obj(&obj) {}
bool Load(const string& config_string) {
stringconnection_string_, command_;
…//从config_string中解析出connection_string_等
_obj-> Connect(connection_string);
_obj-> Load(command_);
}

private:
T*_obj;
};
很简单,很方便,其他代码不用作任何改动。
但是,如果你是一个很注重软件工程和代码优化的程序员。那么,你可能会立刻叫起来:代码重复!
啊,没错。的确重复。实际上,上面这段特化的代码就是我从前一个帖子里直接拷贝过来的。代码重复是软件工程的死敌。所以,我们得消灭它。不过,事情有些麻烦。
由于XmlFromDB和XmlFromIC具备相同的接口形式,所以我们希望它们共用一个特化。但是,C++不允许两个类型共享一个全特化。我们没法写成这样:
template <>
class Adapter <XmlFromDB, XmlFromIC>

或者其它任何类似的形式。
归根结底,我们实际上想要的不仅仅对某个类型的特化,而是要对一组具备某种(接口)特征的类型的特化。这就有点难为C++了。C++不是魔术箱,(不过也已经很接近了),不可能要什么给什么。C++目前做不到这件事情,仅仅是目前。:)
不过,我们还有机会。我们可以利用C++强大的范型编程能力,用一种稍嫌繁琐的方法实现这个功能:
template <typename T>
struct adapter_tag;

template <>
struct adapter_tag <XmlFromNet> ;
{
static const int tag=1;
};

template <>
struct adapter_tag <XmlFromDB> ;
{
static const int tag=2;
};

template <>
struct adapter_tag <XmlFromDisc> ;
{
static const int tag=3;
};

template <>
struct adapter_tag <XmlFromNet> ;
{
static const int tag=2;
};

template <class T, int tag>
class AdapterImpl;

template <class T>
class AdapterImpl <T, 1>
{
public:
AdapterImpl(T& obj)
: _obj(&obj) {}
bool Load(const string& config_string) {
string address_, uid_, psw_, file_name_;
…//从config_string中解析出address_等参数
_obj-> Login(address_, uid_, psw_);
_obj-> Load(file_name_);
}

private:
T*_obj;
};

template <class T>
class AdapterImpl <T, 2>
{
public:
AdapterImpl (T& obj)
: _obj(&obj) {}
bool Load(const string& config_string) {
stringconnection_string_, command_;
…//从config_string中解析出connection_string_等
_obj-> Connect(connection_string);
_obj-> Load(command_);
}

private:
T*_obj;
};

template <class T>
class AdapterImpl <T, 3>
{
public:
AdapterImpl (T& obj)
: _obj(&obj) {}
bool Load(const string& config_string) {
string file_name;
…//从config_string中解析出file_name
_obj-> Load(file_name);
}

private:
T*_obj;
};

template <class T>
class Adapter
: public AdapterImpl <T, adapter_tag <T> ::tag>
{
public:
Adapter(T& obj)


: Adapter(obj){}
};
代码有点复杂,我们一样样看。首先,我们声明了一个结构模板adapter_tag <> 。并对其进行特化。这些特化不干任何事,只定义了一个静态常量成员tag。tag是int类型,每个特化赋予tag一个值。比如用XmlFromNet特化的版本为tag赋值1。请注意,用XmlFormDB和XmlFromIC特化的版本为tag赋的值相同,都是2。这一点很关键。
再来看下一个模板:AdapterImpl <> 。这个模板的代码就使原来Adapter <> 的代码,只是做了少许改动。模板的参数变成了两个:class T和int tag。后一个参数也是C++的绝招。C++允许非类型参数作为模板参数。这里是一个int。但是第一个AdapterImpl <> 的定义有完整的模板参数,但没有模板体,因为我们不需要它(原因上一个帖子已经讲过了)。
紧接着是一个特化。这个特化不同于曾经用过的全特化,他只特化了一个模板参数tag。用一个数字1作为参数的特化值。这叫做局部特化,或部分特化,因为它只特化了部分的模板参数。接下来的两个特化分别用2和3特化了tag参数。
最后,是一个“正常”的类模板Adapter <> ,它继承自AdapterImpl <> 。关键点到了,注意看AdapterImpl的模板参数:AdapterImpl <T, adapter_tag <T> ::tag> 。
T是Adapter <> 的模板参数,这没什么。但第二个模板参数我们用了adapter_tag <T> ::tag作为实参。要说清楚这里的机巧,还得从C++独一无二的编译期计算能力说起。我尽量简单。
当编译器遇到语句:Adapter <XmlFromNet> …时,Adapter就要设法实例化AdapterImpl <> ,因为AdapterImpl <> 是它的基类。实例化是这样的:
AdapterImpl <XmlFromNet, adapter_tag <XmlFromNet> ::tag>
我们略去其他的部分,但看adapter_tag <XmlFromNet> ::tag。这里,用XmlFromNet实例化adapter_tag <> 。因为adapter_tag <> 有好几个特化版本,编译器就在其中寻找匹配的。很幸运,它找到了XmlFromNet的特化。而这个特化中,静态成员变量tag的值是1。因为tag是静态常量,那么这个值在编译期就已经确定。编译器用这个值(1)代替adapter_tag <XmlFromNet> ::tag。于是,AdapterImpl <> 的实例化就变成这样:
AdapterImpl <XmlFromNet, 1>
AdapterImpl <> 也被特化了多次,编译器继续寻找,并很快找到最匹配的那个:AdapterImpl <T, 1> 。于是就是用这个特化的模板做出AdapterImpl <> 的实例化类。最后,产生Adapter <XmlFromNet> 的实际代码。
但是,当编译器遇到Adapter <XmlFromDB> 和Adapter <XmlFromIC> 时,并且发现adapter_tag <XmlFromDB> ::tag和adapter_tab <XmlFromIC> ::tag的值是完全一样的(2)。那么,便一起便会使用同一个AdapterImpl <> 的特化版本:AdapterImpl <T, 2> 来生成最后的代码。
现在来数一下AdapterImpl <> 的特化版本个数,是3个。很好,XmlFromDB和XmlFromIC共享了同一个特化版本:AdapterImpl <T, 2> 。由此,代码得到优化,软件工程性得到保证,而我则得到老板的赏识,以及菜鸟同事的仰慕。;)
作为使用者,你或许问使用起来复杂吗?别担心,使用方法和原来一模一样。连UniLoad()的代码都不用改,所有的工作都在幕后作完了。这就是C++的威力,在使用者不知道,也不需要知道的情况下,无缝、透明地优化了库的代码和结构。若没有强大的抽象能力和扩展能力,是不可能做到的。
最后,我这个爱多事的讨厌鬼,依然不太满意:每增加一个类,就必须做出相应的adapter_tag <> 特化。这些都是手工的,容易出错啊(把tag=2写成tag=3就麻烦了)。能不能直接特化Adapter <> 而无须adapter_tag <> 的帮助呢?能,但不是现在。在未来的C++标准(C++0x)中将会引入concept机制,它便能使我们做到这些。我们充满期待地等待,耐心地等待。


[解决办法]
wa
[解决办法]
嗯,不错哦
[解决办法]
mark++;

读书人网 >C++

热点推荐