【原创&交流】《COM本质论》第一章的有些例子不太恰当

clever101
博客专家认证
2011-08-04 10:38:27
加精
链接:《COM本质论》第一章的有些例子不太恰当


今天在公司的技术沙龙给同事讲解COM,使用了一些《COM本质论》的例子,发现《COM本质论》(英译《Essntial COM》)第一章的有些例子有不恰当的地方。比如1.7节 运行时多态性
原来的字符串类:



IFastString *CallCreateFastSTring(const char *psz){
static IFastString * (*pfn)(const char *) =0;
if(!pfn){
const TCHAR szDLL[]=_TEXT( "FastString.DLL ");
const char szFn[]= "CreateFastSTring ";
HINSTANCWE h= LoadLibrary(szDll);
if (h)
*(FARPROC*)&pfn = GetProcAddress(h,szFN);
}
return pfn?pfn(psz):0;
}



然后为了实现从右向左实现查找,加了个参数bLeftToRight,



IFastString *
CallCreateFastString(const char *char *psz,
bool bLeftToRight =true){
static IFastSTring *(*pfnlr)(const char *) =0 ;
static IFastSTring *(*pfnrl)(const char *) =0 ;

IFaastString *(**ppfn)(const char *)=&pfnlr;
const TCHAR 8pszDll=_TEXT( "FastSTring.Dll ");

if(!bLeftToRight) {
pszDll =_Text( "FastSTringRL.DLL ");
ppfn=&pfnrl;
}

if(!(*ppfn) {
const char szFn[] = "CreateFastString ";
HINSTANCE h =LoadLibrary(pszDll);
if (h)
*(FARPROC *)ppfn =GetProceAddress(h,szFn);
}

return (*ppfn)?(*ppfn)(psz):0;

}




今天有同事问:COM的功能扩展难道采用这种方式吗?我突然发觉1.7节比较奇怪,因为在我看来1.7节所说的运行时多态性根本不是COM的特点,而且这种功能通过设置参数进行扩展本身就非常别扭。COM组件进行功能扩展根本不是新建一个DLL(就是上面提的FastSTringRL.DLL),类似上面提的FastSTringRL.DLL,而是定义一个IFastSTring2: public IFastSTring,然后再从这个类中定义一个从右往左查找的纯虚方法。而且我没听说运行时多态性是COM的特点。

下面一个例子举得更是有些离谱,就是使用C++模拟QueryInterface的实现(我都不太相信当初看这书为何没有疑问):


Void *FastString::Dynamic_Cast(const char *pszType)
{
If(strcmp(pszType,”IFastString”)==0)
return static_cast<IFastString*>(this);
else If(strcmp(pszType,”IPersistentObject”)==0)
return static_cast<IPersistentObject*>(this);
else If(strcmp(pszType,”IExtensibleObject”)==0)
return static_cast<IFastString*>(this);
Return 0;
}



这时有同事质疑:记得有一本书说使用static_cast进行类型转换本身就不是很好的设计。我连忙认真看了一下,发觉搞笑了,居然使用字符串来查找用户所需的接口(重复的概率很大啊!)。COM是通过32位的IID来查找接口的(这样才能确保接口不重复)。其实《COM技术内幕》上有一个QueryInterface的很好的实现:



#include <iostream>
using namespace std;
#include <objbase.h>

void trace(const char* msg)
{
cout << msg << endl;
}


// 接口定义
interface IX : IUnknown
{
virtual void __stdcall Fx() = 0;
};

interface IY : IUnknown
{
virtual void __stdcall Fy() = 0;
};

interface IZ : IUnknown
{
virtual void __stdcall Fz() = 0;
};

// Forward references for GUIDs
extern const IID IID_IX;
extern const IID IID_IY;
extern const IID IID_IZ;

//
// 实现接口 IX,IY(这里表示一个组件)
//
class CA : public IX, public IY
{
//IUnknown implementation
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef() { return 0;}
virtual ULONG __stdcall Release() { return 0;}

// Interface IX implementation
virtual void __stdcall Fx() { cout << "这里是Fx函数" << endl;}

// Interface IY implementation
virtual void __stdcall Fy() { cout << "这里是Fy函数" << endl;}
};

HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IUnknown)
{
trace("QueryInterface: Return pointer to IUnknown.");
*ppv = static_cast<IX*>(this);
}
else if (iid == IID_IX)
{
trace("QueryInterface: Return pointer to IX.");
*ppv = static_cast<IX*>(this);
}
else if (iid == IID_IY)
{
trace("QueryInterface: Return pointer to IY.");
*ppv = static_cast<IY*>(this);
}
else
{
trace("QueryInterface: Interface not supported.");
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef(); // 加计数
return S_OK;
}

//
// 创建类CA,并返回一个指向IUnknown的指针
//
IUnknown* CreateInstance()
{
IUnknown* pI = static_cast<IX*>(new CA);
pI->AddRef();
return pI ;
}

//
// 下面是各接口的IID
//
// {32bb8320-b41b-11cf-a6bb-0080c7b2d682}
static const IID IID_IX =
{0x32bb8320, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

// {32bb8321-b41b-11cf-a6bb-0080c7b2d682}
static const IID IID_IY =
{0x32bb8321, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

// {32bb8322-b41b-11cf-a6bb-0080c7b2d682}
static const IID IID_IZ =
{0x32bb8322, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

//
// 主函数(这里代表客户)
//
int main()
{
HRESULT hr;

trace("Client:获取 IUnknown指针.");
IUnknown* pIUnknown = CreateInstance();

trace("Client:获取接口IX.");

IX* pIX = NULL;
hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
if (SUCCEEDED(hr))
{
trace("Client:获取接口IX成功.");
pIX->Fx(); // 使用 IX.
}

trace("Client:获取接口IY.");

IY* pIY = NULL;
hr = pIUnknown->QueryInterface(IID_IY, (void**)&pIY);
if (SUCCEEDED(hr))
{
trace("Client: Succeeded getting IY.");
pIY->Fy(); // 使用 IY.
}


trace("Client:是否支持接口IZ.");

IZ* pIZ = NULL;
hr = pIUnknown->QueryInterface(IID_IZ, (void**)&pIZ);
if (SUCCEEDED(hr))
{
trace("Client:获取接口IZ成功.");
pIZ->Fz();
}
else
{
trace("Client:获取接口IZ失败,不支持接口IZ.");
}


trace("Client:用接口IX查询接口IY.");

IY* pIYfromIX = NULL;
hr = pIX->QueryInterface(IID_IY, (void**)&pIYfromIX);
if (SUCCEEDED(hr))
{
trace("Client:获取接口IY成功.");
pIYfromIX->Fy();
}


trace("Client:用接口IY查询接口IUnknown.");

IUnknown* pIUnknownFromIY = NULL;
hr = pIY->QueryInterface(IID_IUnknown, (void**)&pIUnknownFromIY);
if (SUCCEEDED(hr))
{
cout << "IUnknown指针是否相等?";
if (pIUnknownFromIY == pIUnknown)
{
cout << "Yes, pIUnknownFromIY == pIUnknown." << endl;
}
else
{
cout << "No, pIUnknownFromIY != pIUnknown." << endl;
}
}

// Delete the component.
delete pIUnknown;

return 0;
}




...全文
2161 84 打赏 收藏 转发到动态 举报
写回复
用AI写文章
84 条回复
切换为时间正序
请发表友善的回复…
发表回复
演地 2011-12-16
  • 打赏
  • 举报
回复
虽然不知道楼上们说什么,但依然觉得楼上们很牛逼。
I_ask_who 2011-12-15
  • 打赏
  • 举报
回复
个人觉得Marshering是个技术瓶颈,突破了就懂了
wutongf 2011-12-05
  • 打赏
  • 举报
回复
第一个例子就更不吐槽了,作者说的是通过纯虚函数来实现用户自定义子类,这个是附带的效果,根本不是为了实现功能扩展,下一张不就是专门在说功能扩展吗
wutongf 2011-12-05
  • 打赏
  • 举报
回复
static_cast是被迫的,因为无法使用虚继承,作者也说了,由于这里仅仅是this指针加一个偏移,所以用static_cast不会造成二义性
  • 打赏
  • 举报
回复
没有看过<COM本质>。

我看的是MSDN
dulvtianya 2011-08-17
  • 打赏
  • 举报
回复
好贴啊,以后再仔细看
shanhe 2011-08-14
  • 打赏
  • 举报
回复
如果严格用复合COM的例子,这不算厚的书可能要增加不少,所以,说明主要矛盾,不一定非得严格遵守COM自身实现吧,再说了,严格实现也有演进改变的一天。

还是眼光放在焦点上吧,效率高点
Blaider 2011-08-12
  • 打赏
  • 举报
回复
有疑问才会讨论,讨论了才会进步……
maoloverme1 2011-08-12
  • 打赏
  • 举报
回复
应该是面向对象软件设计技术
maoloverme1 2011-08-12
  • 打赏
  • 举报
回复
很久以前就看过这一章,觉得对于理解Com的原理有很大的帮助。可惜我没有认真的看完全书。说老实话,到了现在,传统的Com技术现在已经用的不多了,应用起来和了解其原理都过于复杂。但是,要是真正的了解了其原理,对与加强面向软件设计技术和理解C++都是莫大的帮助,可以说是会有本质的提升。我记得2008年的时候还有一本关于ATL原理的很厚的一本书《深入解析ATL》,也很不错的。
backard 2011-08-12
  • 打赏
  • 举报
回复
不会用COM,个人认为COM就是垃圾东西,用COM还不如直接用DLL。
leer168 2011-08-12
  • 打赏
  • 举报
回复
COM的本质不是它如何实现,是COM为什么产生。当时存在什么问题,COM要怎么解决它。能把复杂的理论,讲浅显了,不知道是厉害还是不厉害,LZ自己掂量吧。
冰点青蛙 2011-08-11
  • 打赏
  • 举报
回复
除了听你们bb,其它没学到太多东西!《COM技术内幕》的例子还可以,《COM本质论》的怀疑着看,但人家多数讲的很好,属于必看经典系列。
wsrytang 2011-08-10
  • 打赏
  • 举报
回复
哦,这个说的不错,爱益非浅!
  • 打赏
  • 举报
回复
没有看懂,路过。
a123444646 2011-08-09
  • 打赏
  • 举报
回复
学习一下啊
leslie19771977 2011-08-09
  • 打赏
  • 举报
回复
最近正在学习 下载下来看看
boxun123 2011-08-09
  • 打赏
  • 举报
回复
接分接分
RobbieWilliams 2011-08-09
  • 打赏
  • 举报
回复
路过顺便求分咯
Imoagn 2011-08-09
  • 打赏
  • 举报
回复
楼主敢看完整本书,思考一下再评论吗?这种质疑……CSDN真是各种令人无语的莫名争论贴
加载更多回复(63)

3,245

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧