正如您在下面的代码中看到的,我有一个抽象基类“HostWindow”,以及从它派生的类“Chrome”。所有功能都在 Chrome 中实现。问题是,如果 Chrome 中的函数是虚拟的,我就无法调用它们。
class HostWindow : public Noncopyable {
public:
virtual ~HostWindow() { }
// Pure virtual functions:
virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false) = 0;
virtual void scrollbarsModeDidChange() const = 0;
}
class Chrome : public HostWindow {
// HostWindow functions:
virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false);
virtual void scrollbarsModeDidChange() const;
void focus() const;
}
假设我们有一个 Chrome 实例,我们调用了一些函数:
WebCore::Chrome *chrome = new Chrome();
chrome->repaint(IntRect(), true); // Null pointer error
chrome->focus(); // returns void (works)
每当我调用虚函数时,我得到的空指针错误是:
程序收到信号 EXC_BAD_ACCESS,无法访问内存。原因:KERN_PROTECTION_FAILURE 地址:0x00000008
知道发生了什么吗?
更新: 正如你们中的许多人指出的那样——这段代码实际上是运行的。不幸的是,我无法提供更完整的示例,因为代码在 WebCore (WebKit) 内部很深。但是,我已经缩小了问题的范围。如果我手动创建一个 Chrome 实例,调用虚拟函数就可以了。所以问题出在这个特定的 chrome 实例上——它无法正确实例化。现在,Chrome 实例在另一个类的构造函数中实例化。我会进一步调查...
更新 2: 好的,检查违规实例上的 vtable 显示它为空;来自 GDB:
p *(void **)chrome
$52 = (void *) 0x0
一个普通的实例有一个正确的 vtable。所以,我必须弄清楚为什么 vtable 是 nil - 我想知道这怎么会发生?也许是因为它在其他一些构造函数类中被实例化?
更新 3: 看起来我对问题是正确的,因为它是在另一个类的构造函数中实例化。
所以,在实例化之前看起来像这样:
Page::Page(ChromeClient* chromeClient, ...)
: m_chrome(new Chrome(this, chromeClient))
并且 m_chrome 是一个无效的实例,具有一个 nil vtable。我已经更改了实例化,因此它在第一次需要变量时发生(这涉及保存 ChromeClient 以供以后使用):
Page::Page(ChromeClient* chromeClient, ...)
: m_chrome(0)
, m_chrome_client(chromeClient)
Chrome* Page::chrome() const {
if(!m_chrome) {
m_chrome = new Chrome(this, m_chrome_client);
}
return m_chrome;
}
现在 Page::chrome() 实例是正确的,具有正确的 vtable - 相当奇怪!
更新 4: 最后一次更新,我保证 :)。好的,所以我已经准确地指出了它。如果您在 Page 构造函数的主体中实例化它,您将使用 vtable 获得正确的实例。如果您在 Page 构造函数的头部实例化它,它就没有 vtable。您可以在构造函数的头脑中进行的变量设置类型是否有任何限制?我想这是另一个 Stackoverflow 问题。
谢谢你们这么有帮助。