正如您在下面的代码中看到的,我有一个抽象基类“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是零 - 我想知道怎么会发生这种情况?也许是因为它正在其他一些类Constructor中实例化?
更新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问题。
感谢大家的帮助。
答案 0 :(得分:2)
是的,'this'指针为零。添加8以获得偏移,这是你的错。你显然根本没有任何实际的对象。
由于你没有发布足够的代码来真正掌握,我猜。整个this指针为0,或虚函数表指针为0,可能是因为该对象在创建后以及尝试调用之前已被删除。
我能给你的最好建议是制造一个小得多的试管。要么你会发现你的问题,要么最终得到一个可以举例说明的例子。
在构造过程结束之前,vtbl不在实例中。实际上,规范要求逐步修改vtbl以匹配类层次结构的构造状态。
答案 1 :(得分:0)
你能发布完整的代码吗?
在您的代码稍作修改后(无论什么可用),它可以工作:
#include <iostream>
class HostWindow {
public:
virtual ~HostWindow() { }
// Pure virtual functions:
virtual void repaint(const int , bool contentChanged, bool immediate = false, bool repaintContentOnly = false) = 0;
virtual void scrollbarsModeDidChange() const = 0;
};
class Chrome : public HostWindow {
public:
// HostWindow functions:
virtual void repaint(const int , bool contentChanged, bool immediate = false, bool repaintContentOnly = false)
{
std::cout << "In repaint." << std::endl;
}
virtual void scrollbarsModeDidChange() const { }
void focus() const
{
std::cout << "In focus." << std::endl;
}
};
int main()
{
Chrome *chrome = new Chrome();
chrome->repaint(1, true); // Null pointer error
chrome->focus();
delete chrome;
return 0;
}
答案 2 :(得分:0)
我不熟悉您的代码库,但是您不应该写下以下内容:
// note the 'WebCore::Chrome()'
WebCore::Chrome *chrome = new WebCore::Chrome();
chrome->repaint(IntRect(), true); // 'chrome' should be a valid pointer now
而不是:
WebCore::Chrome *chrome = new Chrome();
chrome->repaint(IntRect(), true); // Null pointer error
答案 3 :(得分:0)
ssume你的不可复制品如下(至少对我来说是这样)
class NonCopyable
{
protected:
NonCopyable() {}
~NonCopyable() {}
private:
NonCopyable( const NonCopyable& );
const NonCopyable& operator=( const NonCopyable& );
};
将 public 修饰符插入到类chrome的函数和一些虚拟实现之后,整个过程没有明确的问题。
发布的代码没有问题,可能是你做错了而且没有在这里发布这些部分。
最后,DO检查分配失败。 (是的,“新”是堆上的分配)
答案 4 :(得分:0)
我发现这是因为允许导出所有符号。
通常,WebCore只有一个符号子集导出 - 基本上是WebKit需要的东西。
我改变了它以导出每个符号 - 它以某种方式导致了这个错误。