在C++中编译时接口实现检查

gga*_*ett 5 c++ inheritance interface multiple-inheritance

我在C++中使用伪接口,即纯抽象类.假设我有三个接口,IFoo,IBar和IQuux.我还有一个Fred类,它实现了所有这三个:

interface IFoo
{
    void foo (void);
}   

interface IBar
{
    void bar (void);
}

interface IQuux
{
    void quux (void);
}   

class Fred : implements IFoo, IBar, IQuux
{
}
Run Code Online (Sandbox Code Playgroud)

我想声明一个接受任何实现IFoo和IBar的对象的方法 - 例如Fred会工作.我能想象的唯一编译时这样做的方法是定义一个实现它们的第三个接口IFooAndBar,并重新声明Fred:

interface IFooAndBar : extends IFoo, IBar
{   
}

class Fred : implements IFooAndBar, IQuux
{
}
Run Code Online (Sandbox Code Playgroud)

现在我可以将我的方法声明为接收IFooAndBar*.到现在为止还挺好.


但是,如果我还想要一个接受IBar和IQuux的不同方法,会发生什么?我尝试声明一个新的接口IBarAndQuux并声明Fred继承两者:

class IFooAndBar : IFoo, IBar
{
};


class IBarAndQuux : IBar, IQuux
{
};


class Fred : IFooAndBar, IBarAndQuux
{
};
Run Code Online (Sandbox Code Playgroud)

当我将Fred作为IFooAndBar传递给方法时,这种方法有效; 但是,当我尝试直接调用Fred :: bar()时,gcc会抱怨:

error: request for member ‘bar’ is ambiguous
error: candidates are: void IBar::bar()
error:                 void IBar::bar()
Run Code Online (Sandbox Code Playgroud)

这使得这种解决方案或多或少无用.


我的下一个尝试是将Fred声明为继承三个单独的接口,并使该方法接受其中一个混合接口作为参数:

class Fred : public IFoo, public IBar, public IBaz
{

};

void doTest (IBarAndBaz* pObj)
{
    pObj->bar();
    pObj->baz();
}
Run Code Online (Sandbox Code Playgroud)

当我尝试将Fred作为IBarAndBaz*参数传递时,我收到错误,如预期的那样:

error: cannot convert ‘Fred*’ to ‘IBarAndBaz*’ for argument ‘1’ to ‘void doTest(IBarAndBaz*)’
Run Code Online (Sandbox Code Playgroud)

dynamic_cast <>也会产生错误(我不明白)

error: cannot dynamic_cast ‘pFred’ (of type ‘class Fred*’) to type ‘class IBarAndBaz*’ (source type is not polymorphic)
Run Code Online (Sandbox Code Playgroud)

但是,强制转换确实有效:

doTest((IBarAndBaz*)pFred);
Run Code Online (Sandbox Code Playgroud)

但我想知道这是多么安全和便携(我为Linux,Mac和Windows开发),以及它是否适用于真实世界的情况.


最后,我意识到我的方法可以接受指向其中一个接口的指针,并将dynamic_cast接受到其他接口以在运行时强制执行正确的参数类型,但我更喜欢编译时解决方案.

Geo*_*che 7

首先考虑使用经过测试的解决方案 - Boost.TypeTraits来救援:

template<class T>
void takeFooAndBar(const T& t) {
    BOOST_STATIC_ASSERT(
           boost::is_base_of<IFoo, T>::value 
        && boost::is_base_of<IBar, T>::value);
    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

  • 在提升之外还有一个世界:-) (2认同)