CSDN博客

img xiaohyy

atl中常见的模板使用手法

发表于2004/7/9 18:54:00  2100人阅读

1、传入基类,继承实现
在设计com接口时,经常会遇到这样的情况:设计一个基接口,其他多个接口继承该接口。一个典型的例子是IUnknown接口,所有的com接口必须从IUnknown接口继承,而这些接口的实现都是相同的,我们不可能为每一个com接口写一个IUnknown接口的实现。IUnknown接口的实现比较复杂,分布在几个类中(可参考《深入解析atl》)。比较直观的一个例子是IDispatch接口的实现,通常需要实现IDispatch接口的类都从IDispatchImpl继承。这个结构是这样的:

class ATL_NO_VTABLE Cbbb :
 public IDispatchImpl<Ibbb, &IID_Ibbb, &LIBID_AAAALib>

template <class T, ...>
class ATL_NO_VTABLE IDispatchImpl : public T
               
这样,每个需要实现IDispatch接口的类都只需要从IDispatchImpl继承即可。
IDispatchImpl的做法其实相当简单,仅仅是引入了一个实现类而已。
另一种常见的情况是分离接口和实现。比如有以下的接口继承结构:
interface IBase
{
    virtual void A()=0;
};
interface IDerive1 : public IBase
{
    virtual void D1()=0;
};
interface IDerive2 : public IBase
{
    virtual void D2()=0;
};
IBase对应的实现类如下:
class CBase : public IBase
{
    virtual void A(){...}
};
这里假设有一个类CDerive1需要继承接口IDerive1和实现类CBase,如果直接从两个类继承,象这样:
class CDerive1 : public CBase,public IDerive1
{
public:
    void D1(){}
};
当使用CDerive1类时,编译器会抱怨模棱两可。很自然的,考虑到用虚拟继承解决:
interface IDerive1 : virtual public IBase
{
    virtual void D1()=0;
};
class CBase : virtual public IBase
{

public:
    virtual void A(){...}
};
class CDerive1 : public CBase,public IDerive1
{
public:
    void D1(){}
};
一切看起来都很完美,virtual继承解决了模棱两可问题。但是虚拟继承是很多产生复杂性问题的根源,难以扩展和维护.
看来我们还是只有老老实实加一个中间层吧。最终解决方案如下:

template<typename TBase>
class CBase : public TBase
{
public:
    virtual void A(){...}
};
class CDerive1 : public CBase<IDerive1>
{
public:
    void D1(){}
};

2、传入子类
在atl中,有大量的以下用法:
template<typename T>
class CB
{
public:
    void Fun1()
    {
        T* pT = static_cast<T*>(this);
        pT->FunD(); //调用T的函数
    }
};
这里传进来的是CB的子类
class CD : public CB<CD>
{
public:
    void FunD(){...}
};

这种技术实际上有点象虚函数.

以上语句T* pT = static_cast<T*>(this)之所以能编译通过是因为模板类CB在编译期间已被实例化为CB<CD>,编译器已经知道T就是CD,而CD继承自CB,所以从CB向CD转型是安全的.这种手法的一个好处是不需要一个T类型的对象,直接可以使用this指针安全转型.其2,避免了虚函数调用的开销,虽然虚函数的开销是很小的,单继承情况下几乎可以忽略不计,但是虚函数的存在不利于编译器的优化,而且static和inline虚函数也要出问题.

 

 

 

 

 

 


 

0 0

相关博文

我的热门文章

img
取 消
img