有效的使用和设计COM智能指针——条款27:考虑__uuidof与uuid在关键字在不同编译器上的兼容问题
2011-09-22 09:10
741 查看
条款27:考虑__uuidof与uuid在关键字在不同编译器上的兼容问题
更多条款请前往原文出处:http://blog.csdn.net/liuchang5你可能还记得条款11中提出的“不轻易舍弃编译器为我们提供的安全机制”,我们因为提倡更加安全的代码而使用了uuid 和__uuidof等关键字。它确实方便了开发,也使得开发的程序在类型上更加安全。
但你可能会考虑到移植问题。我们不指望COM在非windows平台运行,但却不是说C++开发COM只能在VC这个编译器上编译。如果没有VC的话,使用__uuidof和uuid的关键字的智能指针能否继续使用呢?
_com_ptr_t为我们提供了一个折中方案。我们可以在他定义只是决定是否使用uuidof关键字:
//不使用__uuidof关键字 _COM_SMARTPTR_TYPEDEF(ICalculator, IID_ICALCULATOR); //使用uuidof关键字 _COM_SMARTPTR_TYPEDEF(ICalculator, __uuidof(ICalculaor));
而CComPtr则显得不那么客气了。他在代码实现过程中直接使用了__uuidof关键字。这使得我们要在非VC编译器下使用这类智能指针碰到了不少麻烦。
那让我来介绍一个技巧,它可以让你在几乎所有的C++编译器中都可以用__uuidof这个关键字。而条件是,你的C++编译器应该支持模版特化这种特性【11】【12】。
首先我们设计一个可以将"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"形式的GUID转换成GUID类型的函数。当然我们还应当考虑GUID字串两端加入大括号的情况,下面这个函数可以很方便的完成这一点
inline STDMETHODIMP_(GUID) GUIDFromString(LPOLESTR lpsz) { HRESULT hr; GUID guid; if (lpsz[0]=='{') { hr=CLSIDFromString(lpsz,&guid); } else { std::basic_string<OLECHAR> strGuid; strGuid.append(1,'{'); strGuid.append(lpsz); strGuid.append(1,'}'); hr = CLSIDFromString((LPOLESTR)strGuid.c_str(),&guid); } assert(hr==S_OK); return guid; }
我们再来写一个trait类以及针对于这个trait类的一个特化版本。不过这个特化版本我们将其放入到一个宏内部。让用户通过宏来定义出特化的特化后的trait类。
template <class Class> struct _UuidTraits { }; #define _DEFINE_UUID(Class,uuid) \ template <> \ struct _UuidTraits<Class>{ \ static const GUID& Guid(){ \ static GUID guid=GUIDFromString(L## uuid); \ return guid; \ } \ }
之后就能定义一个__uuidof宏。用以模仿vc编译器中__uuidof宏的功能,他实际上会去调用特化后的Trait类:
#define __uuidof(Class) _UuidTraits<Class>::Guid()
最后我们定义一个将GUID和接口绑定起来的宏,那么以后只要使用这个宏就可以将GUID和类绑定在一起。
#define DEFINE_CLSID(Class,guid) \ class Class; \ _DEFINE_UUID(Class,guid) #define DEFINE_IID(Interface,iid) \ struct Interface; \ _DEFINE_UUID(Interface,iid)
OK~,一切都完成了,我们稍微测试一下。
DEFINE_IID(Interface,"{B372C9F6-1959-4650-960D-73F20CD479BB}") DEFINE_IID(Class,"{B372C9F6-1959-4650-960D-73F20CD479AA}") void test() { CLSID clsid=__uuidof(Class); IID iid=__uuidof(Interface); ... }
利用以上这些技巧我们可以很方便的塑造出跨编译器的__uuidof关键字,智能指针代码可以复用,而类型也变得更加的安全。
嗯~ 看来CComPtr的设计者也非圣贤。这种使得接口不易被误用的技术并非一开始则被引入到了这套智能指针中。但随着智能指针被广泛使用,误操作的情况也开始引起智能指针设计者的重视。ATL对此问题也就采取了补救措施。
我们应当时刻警惕,且时刻谨记这一条款“接口应当容易被使用而不易被误用”。
相关文章推荐
- 有效的使用和设计COM智能指针——条款25:思考兼容取地址操作符带来的若干问题
- 有效的使用和设计COM智能指针——条款17:重载运算符时应当符合C/C++约定
- 有效的使用和设计COM智能指针——条款21:巧妙的将对象伪装成指针
- 有效的使用和设计COM智能指针——条款1:智能指针之前世今生
- 有效的使用和设计COM智能指针——条款2:引用计数的是与非
- 有效的使用和设计COM智能指针—条款4:理解ATL的CComPtr提倡简单
- 有效的使用和设计COM智能指针——条款22:果断放弃二进制重用,而采用模版编写智能指针
- 有效的使用和设计COM智能指针——条款18:重载运算符不应当扭曲其语义
- 有效的使用和设计COM智能指针——条款3:按照功能和实现原理选择合适的智能指针
- 有效的使用和设计COM智能指针——条款10:尽量减少智能指针和接口指针的混用
- 有效的使用和设计COM智能指针——条款19:在接口完满的前提下使之最小化。
- 有效的使用和设计COM智能指针——条款23:为例外条件准备应对策略。
- 有效的使用和设计COM智能指针——条款4:理解ATL的CComPtr提倡简单,高效
- 有效的使用和设计COM智能指针——条款24:努力使得接口容易被使用而不易被误用。
- 有效的使用和设计COM智能指针 ——条款5:了解_com_ptr_t 设计背后的历史原因
- 有效的使用和设计COM智能指针——条款11:以类型安全的方式创建资源和查询接口
- 有效的使用和设计COM智能指针——条款12:必要时使用attach() 和 detach()调整引用计数
- 有效的使用和设计COM智能指针——条款6:尽量以智能指针替换接口指针
- 有效的使用和设计COM智能指针 ——条款13:必须提前释放COM组件时,别妄想智能指针帮你完成
- 有效的使用和设计COM智能指针——条款20:安全的覆盖掉C++默默为我们编写的函数