19.8.6 interface_cast_base
这3个接口强制类仅仅负责使用恰当的策略类对它们的基类进行参数化,从而使某些特定的特性成为可访问的。实际上所有动作都发生在interface_cast_base之内,如程序清单19.19所示:
程序清单19.19
- template< typename I
- , typename R
- , typename X
- >
- class interface_cast_base
- {
- protected:
- typedef I interface_type;
- typedef R release_type;
- typedef X exception_policy_type;
- protected:
- template <typename J>
- explicit interface_cast_base(J &j)
- : m_pi(do_cast(j))
- {}
- explicit interface_cast_base(interface_type pi)
- : m_pi(pi)
- {
- addref(m_pi);
- }
- ~interface_cast_base()
- {
- if(NULL != m_pi)
- {
- release_type()(m_pi);
- }
- }
- static interface_type do_cast(LPUNKNOWN punk)
- {
- interface_type pi;
- if(NULL == punk)
- {
- pi = NULL;
- }
- else
- {
- REFIID iid = IID_traits<interface_type>().iid();
- HRESULT hr = punk->QueryInterface(iid,
- reinterpret_cast<void**>(&pi));
- if(FAILED(hr))
- {
- exception_policy_type()(hr, iid);
- pi = NULL;
- }
- }
- return pi;
- }
- interface_type const &get_pointer_();
- interface_type get_pointer_() const;
- private:
- interface_type const m_pi;
- private:
- . . . // 拷贝构造函数和拷贝赋值操作符不可访问
- };
上边的代码中有几点值得注意。首先,所有方法都是受保护的(protected),因此它们不能被外界直接使用,从而也就避免了误用,它们只能被派生类使用。其次,正如先前我们曾讨论过的,构造函数具有模板和非模板两个版本,这样一来既支持了泛用性又兼顾了效率。最后,接口指针如果非空的话就会被交给参数化的release_type仿函数进行释放(见interface_cast_base的析构函数),从而按照release_type策略类要求的方式进行释放(与否)。
那么现在就剩下静态方法do_cast()了。do_cast()是所有幕后工作的主使,interface_cast_base会在模板构造函数里调用do_cast()来尝试进行强制。如果给定的接口指针非空,do_cast()就会调用该指针所指接口的QueryInterface()方法来获取用户请求的接口。如果获取成功的话,新的接口将会返回给客户端,如果失败,则调用exception_policy_type仿函数。而在调用exception_policy_type仿函数之后,如果exception_policy_type什么事情都不做, pi就会被置为NULL然后返回给客户端。