Обращение к полям абстрактного класса
Суть, есть базовый абстрактный класс (не пишу виртуальные деструкторы, полагаем это само сабой разумеющимся):
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]
))