如果我必须覆盖非虚拟成员函数怎么办



假设我们有一个提供类的库

struct Base { int foo() { return 42; } };

我无法更改该类。99%的人从不想覆盖foo,因此库设计者没有将其虚拟化。 但是我需要覆盖它:

struct MyClass : Base { int foo() { return 73; } };

更糟糕的是,该库具有接受指向Base的指针的接口。 我想插入MyClass,但是当然,由于foo不是虚拟的,因此接口背后的代码总是调用Base::foo我希望它打电话给MyClass::foo.

我能做些什么呢?是否有一种共同的模式使Base::foo看起来是虚拟的?

实际上,Base::foo QAbstractProxyModel::sourceModel. 我正在实现一个ProxyChain,将许多代理模型抽象为一个。 QAbstractProxyModel::setSourceModel是虚拟的,但QAbstractProxyModel::sourceModel不是,这会带来很多麻烦。

void ProxyChain::setSourceModel(QAbstractItemModel* source_model)
{
  for (auto* proxy : m_proxies) {
    proxy->setSourceModel(source_model);
    source_model = proxy;
  }
  QIdentityProxyModel::setSourceModel(source_model);
}
QAbstractItemModel* ProxyChain::sourceModel() const
{
  return m_proxies.front()->sourceModel();
}

我能做些什么呢?

无。

这就是为什么指南告诉我们,如果我们希望其他人能够"假装"他们的类是我们类的版本,请使用virtual

Base的作者没有这样做,所以你没有那个权力。

就是这样。

我能做些什么呢?

无。如果一个成员函数是非virtual,那么它是非virtual。这意味着代码库中任何位置的任何代码,如果采用Base指针或引用谁调用base->foo,将完全调用并且仅Base::foo。此调用静态(编译时(绑定到它调用的函数。

您不能访问其他人的代码并让他们使用动态绑定。如果他们没有选择参与动态绑定,那么你就不能制作他们。您可以创建自己的派生类并编写自己的foo版本,以隐藏基类版本。但这不会影响任何获得指向Base的指针/引用的代码的行为。

在特定情况下,最好的办法是确保使用您希望sourceModel在更改时返回的对象调用基类setSourceModel,从而更改sourceModel应该返回的内容。

最新更新