Обращение к полям абстрактного класса
Суть, есть базовый абстрактный класс (не пишу виртуальные деструкторы, полагаем это само сабой разумеющимся):
class Base
{
public:
virtual void foo() = 0;
};
Есть какая-то реализация этого абстрактного класса:
class Impl : public Base
{
public:
void foo()
{
std::cout << "Impl::foo()" << std::endl;
}
};
Проблема может возникнуть в таком коде:
class SomeClass
{
public:
SomeClass()
{
init();
}
~SomeClass()
{
delete ptr;
}
void call()
{
ptr->foo();
}
private:
void init()
{
if (ptr == 0)
ptr = new Impl();
}
Base *ptr;
};
Видите проблему? Что произойдёт когда вы вызовете метод call() у экземпляра класса SomeClass? Что произойдёт когда вы попытаетесь разрушить экзампляр класса SomeClass?
Ответы на два последних вопроса: неожиданное поведение, в большинстве случаев - segmemtation fault. Ответ на вопрос “почему так происходит?” вытекает из ответа на первый вопрос: мы забыли присвоить ptr значение 0 и на момент вызова init() она может быть равно чему угодно, как результат, вызова ptr = new Impl() может и не быть, а значит и указатель в таблице виртуальных функций для foo тоже может глядеть куда угодно.
В gdb в таких случаях мы можем наблюдать подобный вывод:
warning: can't find linker symbol for virtual table for 'Base' value
((При запуске отладки из Qt Creator’а первого слова warning: не будет, а в окне Locals and Expressions вы не сможете просмотреть иерархию “битого” экземпляра, либо увидите кашу в секции [vptr]))