如何在C++中使用非虚拟接口惯用法实现接口类?

and*_*ykx 3 c++ idioms interface non-virtual-interface

在C++中,接口可以由类实现,其所有方法都是纯虚拟的.

这样的类可以是库的一部分,用于描述对象应该实现哪些方法以便能够与库中的其他类一起使用:

class Lib::IFoo
{
    public:
        virtual void method() = 0;
};
Run Code Online (Sandbox Code Playgroud)

:

class Lib::Bar
{
    public:
        void stuff( Lib::IFoo & );
};
Run Code Online (Sandbox Code Playgroud)

现在我想使用类Lib :: Bar,所以我必须实现IFoo接口.

为了我的目的,我需要一个完整的相关类,所以我想使用一个基类来保证使用NVI习语的常见行为:

class FooBase : public IFoo // implement interface IFoo
{
    public:
        void method(); // calls methodImpl;

    private:
        virtual void methodImpl();
};
Run Code Online (Sandbox Code Playgroud)

非虚拟接口(NVI)习惯用法应该拒绝派生类覆盖实现的公共行为的可能性FooBase::method(),但是由于IFoo使其成为虚拟,所以派生类似乎都有机会覆盖FooBase::method().

如果我想使用NVI成语,除了已经建议的pImpl成语之外我还有什么选择(感谢space-c0wb0y).

Mic*_*son 5

我认为你的错误方式是你的NVI模式:http: //en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface

不确定这是否能解决您的问题.

class IFoo
{
    public:
       void method() { methodImpl(); }
    private:
       virtual void methodImpl()=0;
};

class FooBase : public IFoo // implement interface IFoo
{
    private:
        virtual void methodImpl();
};
Run Code Online (Sandbox Code Playgroud)

下面是一个示例,说明为什么您可以使用从XML读取而另一个从DB读取的读取器来执行此操作.请注意,公共结构被移动到NVI readFromSource中,而非常见行为被移动到私有虚拟getRawDatum中.这种方式只需要在一个函数中进行日志记录和错误检查.

class IReader
{
  public:
    // NVI
    Datum readFromSource()
    {
       Datum datum = getRawDatum();
       if( ! datum.isValid() ) throw ReaderError("Unable to get valid datum");
       logger::log("Datum Read");
       return datum;
    }
  private:
    // Virtual Bits
    Datum getRawDatum()=0;
};

class DBReader : public IReader
{
  private:
    Datum getRawDatum() { ... }
};

class XmlReader : public IReader
{
   private:
     Datum getRawDatum() { ... }
};
Run Code Online (Sandbox Code Playgroud)