Как вы можете видеть из кода ниже, у меня есть абстрактный базовый класс "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 на экземпляре-нарушителе показывает, что он нулевой; из ГБД:
p *(void **)chrome
$52 = (void *) 0x0
Нормальный экземпляр имеет правильный vtable. Итак, я должен выяснить, почему vtable равен нулю - интересно, как это могло произойти? Может быть, потому что он создается в некоторых других классах конструктора?
Обновление 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;
}
Теперь экземпляр Page :: chrome () правильный, с правильным vtable - довольно странно!
Обновление 4:
Последнее обновление обещаю :). Итак, я точно определила это. Вы получаете правильный экземпляр с помощью vtable, если создаете его экземпляр в теле конструктора Page. Если вы создадите его в голове конструктора Page, у него нет vtable. Есть ли какие-либо ограничения в типах установки переменных, которые вы можете сделать в голове конструктора? Я думаю, это еще один вопрос Stackoverflow.
Спасибо, ребята, за помощь.