Инструменты пользователя

Инструменты сайта


Заметки об отладке

Обращение к полям абстрактного класса

Суть, есть базовый абстрактный класс (не пишу виртуальные деструкторы, полагаем это само сабой разумеющимся):

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

1)

1)
При запуске отладки из Qt Creator'а первого слова 'warning: ' не будет, а в окне 'Locals and Expressions' вы не сможете просмотреть иерархию «битого» экземпляра, либо увидите кашу в секции '[vptr]'