C++ 的 idioms(五)

calling virtuals in constructor

这个一般有两种策略,一个是使用 two-phase,即在 constructor 里面调用一个类似 init 的函数,在这个 init 函数中调用 virtual function 即可,如果不可以修改 constructor,也可以考虑创建一个 factory(或者作为类的 static 方法或者独立的),在生成对象后立即调用对应的 init 函数。

事实上 one phase 的策略是使用 CRTP,在构造函数中 bind 到每个“子类”静态的对应函数上。需要注意的是这其实对应的并非一个常意下的 hierarchy。

capability queries

这个其实是 dynamic_cast 的应用,假如说我们有若干 interface(或者说 pure abstract classs),然后某些类实现了其中一部分,有些实现了另外一部分,我们可能需要对某些 interface 进行检查是否存在对应的能力:

struct rollable {
  virtual void roll () = 0 ;
} ;

class shape {
 // something here
} ;

class circle : public shape, public rollable {
  // implementation
} ;

class square : public shape {
  // not rollable
} ;

std::vector<shape*> v ;
// let's see who may roll
for (int i = 0 ; i < v.size () ; ++ i)
  if (dynamic_cast<rollable*> (v[i]))
    v[i].roll () ;

这个 idiom 的另一个用处是在处理 acyclic visitor pattern 里面,我们知道 run-time visitor 一般具有下面的结构

// in host.hpp
#include "visitor.hpp"
struct host {
  virtual void accept (visitor& v) = 0 ;
} ;

// in visitor.hpp
#include "widget_host.hpp"
#include "window_host.hpp"
struct visitor {
  void do_something (widget_host&) {}
  void do_something (window_host&) {}
} ;

// in some concrete implementation of host
#include "host.hpp"
struct widget_host : public host {
} ;

// in some concrete visitor implementation
#include "visitor.hpp"
struct cyclic_visitor : public visitor {
} ;

这样就产生了循环依赖,这样我们往往去掉 visitor 里面的实现函数,这样就变成一个空壳,而在 visitor 子类里面去实现。这样具体的 host 接受抽象的 visitor,利用这个 idiom 判断 capability 即可。

// in host.hpp
#include "visitor.hpp"
struct host {
  virtual void accept (visitor& v) = 0 ;
} ;

// in visitor.hpp
struct visitor {
} ;

// in some concrete implementation of host
#include "host.hpp"
#include "widget_visitor.hpp"
struct widget_host : public host {
  void accept (visitor& v) {
    if (dynamic_cast<widget_vistor*> (&v)) {
      v.do_something (*this) ;
    }
  }
} ;

// in some concrete visitor implementation
#include "visitor.hpp"
struct widget_visitor : public visitor {
  void do_something (widget_host&) {}
} ;

checked delete

这个就是保证调用 delete 的时候的确调用的是对应的 complete type 的 destructor,早些时候在讨论 boost.utility 的时候见过类似的 code,

// from [include]/boost/checked_delete.hpp
template<class T> inline void checked_delete(T * x) {
  // intentionally complex - simplification causes regressions
  typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
  (void) sizeof(type_must_be_complete);
  delete x;
}

可以看出来前面就是测试 T 的大小,这样对 incomplete type 就会出现 -1,不知道什么情况下第一行会不报错呢?

——————
And blessed be the most high God, which has delivered your enemies into your hand. And he gave him tithes of all.

Advertisements
C++ 的 idioms(五)

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s