描述:
atl为什么要使用template/模板?
大概知道是可以用template技术取代了虚函数开销,
但是,到底是怎么用template实现的啊?
有详细一点的文章吗?
解决方案1:
COM只支持接口继承,而不支持实体继承,所以无法在设计COM组件的时候通过C++实体继承的方式来重用代码,举个例子,如果我有个IUnknowne的实现
class CUnknown : public IUnknown
{
public:
HRESULT QueryInterface( ... );
LONG AddRef();
LONG Release();
};
然后我有个从IUnknown派生的接口IMyInterface
interface IMyInterface : IUnknown
{
HRESULT MyFunc();
};
我不可能通过简单的继承CUnknown然后再加入一个MyFunc的实现来实现IMyInterface, 也就是说这里无法使用C++的实体继承。
当然你说我可以通过虚拟继承的方式来支持这个,但是这样一来,接口就不能维持它的
简单性, 例如,如果COM支持虚拟继承,那么用C++抽象类描述的IUnknown接口和IMyInterface就应该是这样定义的:
class IUnknown
{
public:
virtual HRESULT QueryInterface( ... ) = 0;
virtual LONG AddRef() = 0;
virtual LONG Release() = 0;
};
class IMyInterface : virtual public IUnknown
{
public:
virtual HRESULT MyFunc() = 0;
};
需要注意的是上面的IMyInterface的定义和不通过虚拟继承的IMyInterface是不一样的
下面是不通过虚拟继承的IMyInterface的定义
class IMyInterface : public IUnknown
{
public:
virtual HRESULT MyFunc() = 0;
};
如果IMyInterface通过虚拟继承派生IUnknown, 那么虚拟表就会非常复杂,而不仅仅是一个平面的函数指针表那么简单,而且虚拟继承会带来时间和空间上的额外开销。
但是如果使用模板,那么这些问题都可以解决。通过使用模板,我们可以将需要实现的接口延迟到模板实例化的时候确定。
比如我只需要将原来的CUnknowne的实现改成模板类。
template<class InterfaceType>
class CUnknown : public InterfaceType
{
HRESULT QueryInterface( ... );
LONG AddRef();
LONG Release();
};
而CMyInterface的实现可以是
class CMyInterface : public CUnknown<IMyInterface>
{
public:
virtual HRESULT MyFunc() {};
};
在CMyInterface的实现里,我们给CUnknown模板提供一个参数 - IMyInterface, 通过这种方式我们实现代码的重用。
当然,为了更大的灵活性,我也可以将CMyInterface改变成一个模板类
template<class InterfaceType>
class CMyInterface : public CUnknown<InterfaceType>
{
public:
virtual HRESULT MyFunc() {};
};
这样,当我需要派生IMyInterface的时候,例如
interface IMyInterfaceEx : IMyInterface
{
HRESULT MyFuncEx();
};
我就可以这样子实现:
class CMyInterfaceEx : public CMyInterface<IMyInterfaceEx>
{
public:
HRESULT MyFuncEx() {}
}
当然这种代码重用的方式和C++的基于实体继承或者组合或者虚拟继承的方式都不一样。
接口的继承关系
而又不需要每个人都来自己写基接口的实现
仔细研究一下 IDispatchImpl, 就会明白了
每写个com都要手动写一些几乎相同的代码,而且这些代码很容易出错eg:idl。显得特别繁琐,atl可以消除你的烦恼。最好看看《atl深入解析》
解决方案4:比如IUNKNOWN,IDISPATCH,IPERSISTER,等好大批的接口的实现就那么模式化的几套,与我们的对象的类型没有关系,所以可以在不知道我们的类型的情况下实现出来,这不就是泛型编程吗?
解决方案5:详细的文章也讲不清楚这些问题,<<ATL INTERNALS>>讲的就很清楚.虚函数的开销是不可能取消的,这是COM的技术基础.使用template是用泛型编程,特别适合用C++来开发COM组件

