当前位置:编程学习 > C/C++ >>

有效的使用和设计COM智能指针——条款11

条款11:以类型安全的方式创建资源和查询接口
下面这种写法在COM组件编写过程中这种错误的写法并不少见:

view plaincopy to clipboardprint?void func() 

    IX *pIX  = NULL; 
    hrRetCode = CoCreateInstance(  
        CLSID_MYCOMPONENT, 
        NULL, 
        CLSCTX_INPROC_SERVER, 
        IID_IX  
        (void **)pIX         //额~~阴沟里翻船了~  
    ); 
    assert(hrRetCode); 
    pIX->IxFunction(); 
}                              
void func()
{
    IX *pIX  = NULL;
    hrRetCode = CoCreateInstance(
        CLSID_MYCOMPONENT,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IX
        (void **)pIX         //额~~阴沟里翻船了~
    );
    assert(hrRetCode);
    pIX->IxFunction();
}                            
 
上述代码会发生什么?其行为不确定,而且在大多数情况下是错误的。原因是由于创建COM组件或者接口查询的时候使用的函数并非类型安全的。

针对这种情况,你可能会想到我们应该多利用智能指针来避免这一问题。因为智能指针无法强制转换成(void**)类型。貌似这样做能使得你的类型变得安全一些,然而错误还是发生了:

view plaincopy to clipboardprint?void func() 

    CComPtr<IX> spIX  = NULL; 
    hrRetCode = CoCreateInstance(  
        CLSID_MYCOMPONENT, 
        NULL, 
        CLSCTX_INPROC_SERVER, 
        IID_IY             //额~~这里又出错了 :(  
        (void **)&pIX  
    ); 
    assert(hrRetCode); 
    pIX->IxFunction(); 
}                              
void func()
{
    CComPtr<IX> spIX  = NULL;
    hrRetCode = CoCreateInstance(
        CLSID_MYCOMPONENT,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IY             //额~~这里又出错了 :(
        (void **)&pIX
    );
    assert(hrRetCode);
    pIX->IxFunction();
}                            
好在后面的断言能将错误及时的反馈上来,但是如果我们有更好的方法来避免这一问题的出现,为何不用呢?

解决这一问题的最好方式是用智能指针所提供的接口查询方法:

view plaincopy to clipboardprint?void func() 

    CComPtr<IX> spIX  = NULL;    //IID在智能指针创建的时候与其绑定在一起  
    spIX .CoCreateInstance(CLSID_MYCOMPONENT); 
    assert(spIX ); 
    pIX->IxFunction(); 
}                              
void func()
{
    CComPtr<IX> spIX  = NULL;    //IID在智能指针创建的时候与其绑定在一起
    spIX .CoCreateInstance(CLSID_MYCOMPONENT);
    assert(spIX );
    pIX->IxFunction();
}                             
是的,这一点没错。我们推荐使用智能指针,但是我们更多的希望的是你通过智能指针提供的功能性函数来完成资源的创建与查询。他不仅带来了了代码上的简洁,而且使得你的代码在类型上更加的安全。

有时候,我们在考虑设计某个类时,通常会考虑他的移植性和兼容性。这导致我们会慎重的采用一些与编译器相关的特性时,往往采用了谨慎的态度。或者更多时候,我们避讳编译器给我们带来的某些特性,来追求可移植和不同平台下的兼容性。

但值得注意的是,在考虑这些问题之前,我们先应该考虑的是程序的正确执行。一个允许错误肆意存在的程序,即便是可以随意移植,意义也不会很大。

首先看一眼下面这套接口和GUID的定义:

view plaincopy to clipboardprint?// {994D80AC-A5B1-430a-A3E9-2533100B87CE}  
DEFINE_GUID(IID_ICALCULATOR,  
            0x994d80ac, 0xa5b1, 0x430a, 0xa3, 0xe9, 0x25, 0x33, 0x10, 0xb, 0x87, 0xce);  
class ICalculator public : IUnknown 

public: 
    virtual HRESULT STDMETHODCALLTYPE Add( 
        const int nNum1,  
        const int nNum2,  
        int *pnSum 
    ) const = 0; 
     
    virtual HRESULT STDMETHODCALLTYPE Sub( 
        const int nMinuend, 
        const int nSubtrahend,  
        int *pnQuotient 
    ) const = 0; 
};                     
// {994D80AC-A5B1-430a-A3E9-2533100B87CE}
DEFINE_GUID(IID_ICALCULATOR,
            0x994d80ac, 0xa5b1, 0x430a, 0xa3, 0xe9, 0x25, 0x33, 0x10, 0xb, 0x87, 0xce);
class ICalculator public : IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE Add(
        const int nNum1,
        const int nNum2,
        int *pnSum
    ) const = 0;
   
    virtual HRESULT STDMETHODCALLTYPE Sub(
        const int nMinuend,
        const int nSubtrahend,

补充:软件开发 , C语言 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,