【问题标题】:Enforce third party methods virtuality强制第三方方法虚拟化
【发布时间】:2010-08-31 15:03:18
【问题描述】:

我正在扩展由第三方库提供的类。这个类,我们称之为Foo,有一个reset() 方法,可以调用它来重新启动Foo 的行为。 reset() 方法也在类内部使用。

class Foo
{
  public:
    void reset () {
        /* ... */
    }
    void something () {
        reset();
    }
};

到目前为止,我还需要重载 reset() 方法以重置我的附加功能:

class Bar : public Foo
{
  public:
    void reset() {
        /* ...something... */
        Foo::reset();
    }
};

不幸的是,由于Foo::reset() 方法不是虚拟的,通过调用Bar::something() 我得到的是Foo::reset() 方法而不是Bar::reset()

有没有办法(也不同于重载Foo::something())使其向后虚拟化?

【问题讨论】:

  • 顺便说一句,通过这种方式,我学会了始终将任何公开和内部使用的方法设置为虚拟。
  • 这是一个糟糕的决定,谷歌搜索 NVI,你会看到避免公共虚拟方法的趋势。你面临的问题是不同的:你不能扩展一个不是为扩展而设计的类。
  • 我强烈支持非虚拟接口。使用 virtual 公共方法类似于将句柄返回到您的内部 -> 这是一个不可以。
  • 在 Bar 中,您既不会重载(Bar 和 Foo 的 reset 具有相同的签名)也不会覆盖它(因为 Foo 的 reset 不是虚拟的);你隐藏了 Foo 的reset()

标签: c++ virtual


【解决方案1】:

您不能扩展不打算扩展的类。

【讨论】:

    【解决方案2】:

    你不能在你的库中将reset() 设为虚拟,这样它就会影响基类而不更改基类的代码。对于初学者来说,编译器没有添加必要的簿记代码来允许它对reset()进行虚拟调用。

    【讨论】:

      【解决方案3】:

      没有使用继承的“干净方式”。虚拟是编译/链接时间差异:在运行时使用 vtable 解析方法(虚拟)与直接链接(非虚拟)。

      【讨论】:

        【解决方案4】:

        不,这是不可能的。方法的虚拟性是在声明方法时决定的,以后不能在基类中更改它。

        让你这样做简直就是一场灾难。虚拟方法的行为与非虚拟方法不同,在设计对象时必须考虑到这一点。有了这个提议,我将不得不考虑我所有的方法都可以以两种截然不同的方式表现。这显着增加了应用程序的设计成本并降低了可靠性。

        【讨论】:

          【解决方案5】:

          如果重置或某些东西都不是虚拟的,那么你就完蛋了,这就是故事的结局。如果某些东西是虚拟的,您可以覆盖它。但是,如果这些必要的方法不是虚拟的,则该类不打算被扩展(或正确实现,如果它是打算的)。

          编辑:

          你可以尝试作曲,例如

          class Bar {
              Foo f;
              // foo's methods, etc, wrapped here
              void something() {
                  f.reset();
                  reset();
              }
          };
          

          但如果你需要完整的、隐式的转​​换,那你还是吃不消。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-05-01
            • 2013-10-23
            • 1970-01-01
            • 2018-09-10
            • 1970-01-01
            • 1970-01-01
            • 2015-12-19
            相关资源
            最近更新 更多