C 泛型编程系列讲座之实施

2008-02-23 05:24:55来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

 您知道,当一个概念从一个专有名词变成一个普通名词时,说明他真正的深入人心了。比如Kleenex(面巾纸品牌,也指面巾纸),Xerox(施乐,复印机品牌,也指复印机)Q-Tips(化妆品品牌,也指化妆包),对吗?所以说,当我听说您能够在Visual C .NET中使用“modern C design”时很高兴也就不奇怪了。这里指的是——至少我这样认为——《Modern C Design》[1]所推行的基于模板的技术。

  在任何泛型编程文章中都有一个成功的要素,就是进行特有至通用的“文法升华。”比如,在ScopeGuard[2]中增加了放入“撤消”动作于正常执行路径而当一个复杂操作成功时解除“撤消”的常见技术之后,ScopeGuard就成为了“域守卫(scope guard)”。我大多数受欢迎的文章不完全由我完成,而是和Petru Marginean紧密合作的结果。而且让我更加高兴的是再一次在本文中和他合作。

  本文中我们将讨论对应于发布状态的机制:实施(enforcement),这是方便实用的快速条件验证机制。很类似于ScopeGuard,ENFORCE宏极大程度地减少了您需要使用在错误处理上的代码。ScopeGuard和ENFORCE可相互单独工作,但最好是一起使用。ENFORCE是意外的源头,ScopeGuard是意外的传播者。

  实施(Enforcements)

  设想您注视着面前的一大堆代码。您知道您要在这些代码中杀出一条血路,您也知道您必须写更多的新代码。

  一个好习惯是先浏览代码,试着找到一些通用模式。您要理解模式背后的概念。很有可能,任何这些都不是偶然发生的,而是同样的基本概念的不同表现形式,然后,您能够整理这些提取出的模式,这样您就能够扼要地表达任何的作为概念的实现体的模式

  现在先暂停,看一下您要分析的不同模式的大小。假如这个模式很大,比如作为基础部分涉及到了整个程式,那么您正在和结构模式(architectural patterns)打交道。

  假如模式是中等尺寸,横跨数个对象和/或函数,那么您碰到的是设计模式。

  假如模式很小,只包括3-10行代码,那么您面前的的常用法(idiom)。

  最后,假如模式只有1-2行代码,您得到的东西叫做代码风格或格式。

  这四种根据规模划分的类型所涵盖的范围类似于建筑学。在建筑学中,基本结构的小瑕疵不要紧。在软件架构中,任何缺陷都可能毁掉整个“建筑”。相反,您需要在任何范围使用正确的技术来确保成功。假如您对小细节着迷而忽略大的蓝图,您会浪费才华于建立不能远观的复杂的阿拉伯式建筑。假如您只注重大的方面而忽视细节,您会得到粗糙的庞然大物。

  这是写软件异常困难的原因,这个困难是在其他领域工作的人们不能完全理解的。

  实施属于常用法范畴。周详点说,实施极大简化了错误检测代码而不会影响可读性和正常工作流的流畅性。

  想法来源于下列事实。您抛出一个意外很可能是作为一个布尔值检测的结果,如下:

if (some test)
 throw SomeException(arguments);

  假如该意外在多处出现,为什么不把他放在一个小函数里呢:

template <class E, class A>
inline void Enforce(bool condition A arg)
{
 if (!condition) throw E(arg);
}

  能够这样使用他:

Widget* p = MakeWidget();
Enforce<std::runtime_error>(p != 0, “null pointer”);
Enforce<std::runtime_error>(cout != 0, “cout is in error”);
cout << p->ToString();

  现在为止一切顺利.现在,我们来分析几个重要方面。

  首先,被测条件不总是布尔型的,也可能是个指针或整型。其次,很可能您要在检测完之后马上使用被测值。比如,您可能希望在使用前确保一个指针非空,或您可能要在创建一个文档句柄后马上使用他。所以我们修改Enforce,这样他就有滤过机制来把接受的值传回:

template <class E, class A, class T>
inline T& Enforce(T& obj, A arg)
{
 if (!obj) throw E(arg);
  return obj;
}

template <class E, class A, class T>
inline const T& Enforce(const T& obj, A arg)
{
 if (!obj) throw E(arg);
  return obj;
}

  (两个版本是必须的,分别对应const和非const对象。)您能够增加两个重载版本来表示您通常会抛出的那种意外和他所带参数。

Template <class T>
Inline T& Enforce(T& obj, const char* arg)
{
 return this->Enforce<std::runtime_error, const char*, T>(obj,arg);
}

template <class T>
inline const T& Enforce(const T& obj, const char* arg)
{
 return this->Enforce<std::runtime_error, const char*, T>(obj,arg);
}

  假如您认为应该传入一个通用参数(信息)到std::runtime_error,调用能够进一步简化。您所需做的一些只是增加几个重载函数:

Template <class T>
Inline T& Enforce(T& obj)
{
 return this->EnforceMstd::runtime_error, const char*, T>(obj,“Enforcement error”);
}

template <class T>
inline const T& Enforce(const T& obj)
{
 return this->Enforce<std::runtime_error, const char*, T>(obj,“Enforcement error”);
}

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: C 未来断想

下一篇: C 指针直接调用类成员函数探讨