2010-01-12 3 views
1

Как вы можете видеть в приведенном ниже коде, у меня есть абстрактный базовый класс «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 является недействительным экземпляр, с нулевыми виртуальными таблицами. Я изменил экземпляр, так что происходит, когда первый раз требуется переменный (это включает в себя сохранение 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; 
} 

Теперь страница :: Экземпляра хрома() является правильным, с правильный vtable - довольно странно!

Обновление 4: Последнее обновление, я обещаю :). Хорошо, поэтому я точно определил это. Вы получаете правильный экземпляр с помощью vtable, если вы создаете экземпляр его в теле конструктора страницы. Если вы создаете экземпляр в голове конструктора страницы, у него нет vtable. Есть ли ограничение в настройках переменных, которые вы можете сделать в голове конструктора? Наверное, это еще один вопрос Stackoverflow.

Спасибо, ребята, за то, что они так полезны.

+2

PLease опубликуйте код REAL с помощью копирования и вставки. –

+0

Это настоящий код. Я не могу сделать это более кратким, поскольку это правильно в середине WebKit. –

+0

Какова ценность «chrome» сразу после вызова «WebCore :: Chrome» chrome = new Chrome(); Если NULL, исключение выбрасывается? –

ответ

2

Да, указатель 'this' равен нулю. Добавьте 8, чтобы получить смещение, и есть ваша ошибка. У вас, по-видимому, нет никакого реального объекта.

Поскольку вы не отправили достаточно кода, чтобы действительно прийти в себя, я предполагаю. Либо весь этот указатель равен 0, либо указатель таблицы виртуальных функций равен 0, возможно, потому, что объект был удален после его создания и до того, как вы попытаетесь его вызвать.

Лучший совет, который я могу вам дать, - создать гораздо меньшую пробирку. Либо вы найдете свою проблему, либо вы получите столбец.

vtbl не находится на месте в экземпляре до конца процесса строительства. Фактически, спецификация требует прогрессивной модификации vtbl для соответствия состоянию построения иерархии классов.

+0

Не могли бы вы уточнить?Я довольно новичок в C++. У меня есть экземпляр Chrome, и я могу вызвать некоторые функции - например focus(), но не определенные в ABC, например repaint(). –

+0

«Хром» не является экземпляром, это класс. «Хром» - это пример. –

+0

vtable - nil - см. Обновления. Я понятия не имею, как это могло произойти. –

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; 
} 
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 
+0

Да, это была опечатка в примере. –

+1

@Alex: Вот почему вы всегда должны вырезать/вставлять код. __NEVER__ retype, поскольку он просто добавляет ошибки и приводит к большому количеству нулевой работы для людей, которые помогают вам. –

0

ssume ваш не-Copyable являются следующие (по крайней мере, сделал мой)

class NonCopyable 
{ 
protected: 
    NonCopyable() {} 
    ~NonCopyable() {} 
private: 
    NonCopyable(const NonCopyable&); 
    const NonCopyable& operator=(const NonCopyable&); 
}; 

после вставки общественных модификатора к классу функциям Хрома и фиктивной реализации для них, все это работало без поставленной задачи.

нет никаких проблем с кодом отвечал, это может быть, вы делаете вещи неправильно и не разместить эти части здесь.

наконец, DO проверка отказа распределения. (да, «новые» - выделение на кучу)

+0

Вы читали обновления? –

+0

К сожалению, я сделал ... Что такое класс Страница? u добавлен фрагмент кода без деталей для других людей, чтобы понять – YeenFei

0

Я обнаружил, что это вызвано тем, что разрешено экспортировать все символы.

Как правило, WebCore имеет только подмножество символов, экспортируемых - в основном, на вещи, которые нужны WebKit.

Я изменил это, чтобы экспортировать каждый символ - и это как-то вызвало эту ошибку.