如何在 C++ 中使用非虚拟接口惯用法实现接口类?
在 C++ 中,接口可以由方法为纯虚方法的类实现。
这样的类可以是库的一部分,用于描述对象应该实现哪些方法才能与库中的其他类一起工作::
class Lib::IFoo
{
public:
virtual void method() = 0;
};
现在
class Lib::Bar
{
public:
void stuff( Lib::IFoo & );
};
我想使用类Lib::Bar
,所以我必须实现 IFoo 接口。
出于我的目的,我需要一整套相关的类,因此我想使用一个基类来保证使用 NVI 惯用法的共同行为:
class FooBase : public IFoo // implement interface IFoo
{
public:
void method(); // calls methodImpl;
private:
virtual void methodImpl();
};
非虚拟接口 (NVI) 惯用法应该拒绝派生类重写共同行为的可能性在 FooBase::method()
中实现,但由于 IFoo
将其虚拟化,似乎所有派生类都有机会重写 FooBase::method()
。
如果我想使用 NVI 惯用法,除了已经建议的 pImpl 惯用法之外,我还有什么选择(感谢 space-c0wb0y)。
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 & );
};
Now I want to to use class Lib::Bar
, so I have to implement the IFoo
interface.
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();
};
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()
.
If I want to use the NVI idiom, what are my options other than the pImpl idiom already suggested (thanks space-c0wb0y).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我认为你的 NVI 模式是错误的:
http://en.wikibooks.org/wiki/More_C%2B% 2B_Idioms/Non-Virtual_Interface
但不确定这是否能解决您的问题。
下面的示例说明了为什么您可以使用从 XML 读取的读取器和从 DB 读取的读取器来执行此操作。请注意,常见结构被移至 NVI readFromSource,而非常见行为则移至私有虚拟 getRawDatum。这样,仅在一个函数中需要记录和错误检查。
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.
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.
通常,使用 NVI(有时也称为“模板方法”)的原因是派生类应该只更改基类行为的一部分。因此,您要做的就是:
派生类可以在其应有的位置插入
f()
并更改f()
的方面 > 的行为,而不会扰乱其基本算法。Commonly, the reason for using the NVI (sometimes also called "Template Method") is that derived classes should only change a part of the base class' behavior. So what you do is this:
Derived classes can then plug into
f()
at the spots they are meant to and change aspects off()
's behavior, without messing up its fundamental algorithm.可能会令人困惑的是,一旦一个方法在基类中声明为虚拟方法,它就会在所有派生类中自动变为虚拟方法,即使那里没有使用 virtual 关键字。因此,在您的示例中, FooBase 的两个方法都是虚拟的。
如果您可以摆脱
IFoo
,并使用非虚拟method
以FooBase
启动层次结构>,这样就可以了。但看起来您希望允许IFoo
的直接子级覆盖method()
,但阻止FooBase
的子级覆盖它。我认为这是不可能的。It may be confusing that once a method is declared as virtual in a base class, it automatically becomes virtual in all derived classes, even if the
virtual
keywords is not used there. So in your example, both methods ofFooBase
are virtual.If you can get rid of
IFoo
, and just start the hierarchy withFooBase
with a non-virtualmethod
, that would do it. But it looks like you want to allow direct children ofIFoo
to overridemethod()
, but to prevent children ofFooBase
to override it. I don't think that's possible.您可以使用 pimpl-idiom 来实现此目的:
现在其他人仍然可以子类化
IFooImpl
并将其传递给IFoo
,但他们无法覆盖method
的行为code> (它们可以覆盖otherMethod
)。您甚至可以使IFooImpl
成为IFoo
的直接子类并使用enable_shared_from_this
正确初始化IFoo
。这只是该方法的要点。有很多方法可以调整这种方法。例如,您可以使用 工厂模式 来确保IFoo
s 已正确创建。希望有帮助。
You could use the pimpl-idiom to achieve this:
Now others can still subclass
IFooImpl
and pass it toIFoo
, but they cannot override the behavior ofmethod
(they can overrideotherMethod
). You can even makeIFooImpl
a direct subclass ofIFoo
and useenable_shared_from_this
to initializeIFoo
correctly. This is just the gist of the method. There are many ways to tweak this approach. For instance you can use the factory-pattern to make sureIFoo
s are created correctly.Hope that helps.