如何使用 C++ 中的非虚拟接口习语来实现接口类?
在 C++ 中,接口可以由其方法是纯虚拟的类来实现.
In C++ an interface can be implemented by a class whose methods are pure virtual.
这样的类可以是库的一部分,用于描述对象应该实现哪些方法才能与库中的其他类一起工作:
Such a class could be part of a library to describe what methods an object should implement to be able to work with other classes in the library:
class Lib::IFoo
{
public:
virtual void method() = 0;
};
:
class Lib::Bar
{
public:
void stuff( Lib::IFoo & );
};
现在我想使用类Lib::Bar
,所以我必须实现IFoo
接口.
Now I want to to use class Lib::Bar
, so I have to implement the IFoo
interface.
出于我的目的,我需要一整套相关的类,所以我想使用一个基类来保证使用 NVI 习惯用法的常见行为:
For my purposes I need a whole of related classes so I would like to work with a base class that guarantees common behavior using the NVI idiom:
class FooBase : public IFoo // implement interface IFoo
{
public:
void method(); // calls methodImpl;
private:
virtual void methodImpl();
};
非虚拟接口 (NVI) 习惯用法应该拒绝派生类覆盖在 FooBase::method()
中实现的常见行为的可能性,但是由于 IFoo
使它成为虚拟似乎所有派生类都有机会覆盖 FooBase::method()
.
The non-virtual interface (NVI) idiom ought to deny derived classes the possibility of overriding the common behavior implemented in FooBase::method()
, but since IFoo
made it virtual it seems that all derived classes have the opportunity to override the FooBase::method()
.
如果我想使用 NVI 习语,除了已经建议的 pImpl 习语,我还有什么选择(感谢 space-c0wb0y).
If I want to use the NVI idiom, what are my options other than the pImpl idiom already suggested (thanks space-c0wb0y).
推荐答案
我认为您的 NVI 模式有误:http://en.wikibooks.org/wiki/More_C%2B%2B_惯用语/非虚拟_接口
I think you've got your NVI pattern around the wrong way: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface
不确定这是否能解决您的问题.
Not sure if that solves your issue though.
class IFoo
{
public:
void method() { methodImpl(); }
private:
virtual void methodImpl()=0;
};
class FooBase : public IFoo // implement interface IFoo
{
private:
virtual void methodImpl();
};
这里有一个示例,说明为什么您可以使用从 XML 读取的读取器和从 DB 读取的另一个读取器执行此操作.请注意,公共结构移入 NVI readFromSource,而非公共行为移入私有虚拟 getRawDatum.这种方式只需要在一个函数中进行日志记录和错误检查.
Here's an example of why you might do this using a reader that reads from XML and another from DB. Note that common structure is moved into the NVI readFromSource, while non-common behaviour is moved into the private virtual getRawDatum. This way logging and error checking is only needed in the one function.
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() { ... }
};
相关文章