假设我们有一个提供类的库
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
应该返回的内容。