调用虚函数时继承类“无效指针错误”

时间:2010-01-12 13:33:27

标签: c++ inheritance polymorphism abstract-class abc

正如您在下面的代码中看到的,我有一个抽象基类“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问题。

感谢大家的帮助。

5 个答案:

答案 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需要的东西。

我改变了它以导出每个符号 - 它以某种方式导致了这个错误。