что делать с деструкторами в интерфейсе - PullRequest
7 голосов
/ 19 марта 2011

Когда я пишу интерфейсные классы на C ++, я выбираю один из следующих 2 вариантов

class Interface
{
public:
   virtual R1 f1(p11, p12 , ...) = 0;
   ...
   virtual Rn fn(pn1, pn2 , ...) = 0;
   virtual ~Interface() {} 
}

или

class Interface
{
public:
   virtual R1 f1(p11, p12 , ...) = 0;
   ...
   virtual Rn fn(pn1, pn2 , ...) = 0;
   virtual ~Interface() = 0; 
}
Interface::~Interface() {}

Первая версия короче, чтобы написать
Второе привлекательно тем, что все функции интерфейса чисто виртуальные

Есть ли причина, по которой я предпочитаю тот или иной метод (или, возможно, третий)?
Спасибо

Ответы [ 4 ]

5 голосов
/ 19 марта 2011

Как я понимаю, цель создания виртуальной функции чисто виртуальной состоит в том, чтобы заставить производные классы либо предоставить реализацию для нее, либо выбрать реализацию по умолчанию с помощью явно записи Base::f()в Derived::f().

Итак, если это правда, тогда какова цель создания виртуального деструктора pure virtual?Вынуждает ли производные классы обеспечивать реализацию для Base::~Base()?Могут ли производные классы реализовать Base::~Base()?Нет.

Значит, первая версия с деструктором virtual кажется достаточной для почти всех целей.В конце концов, наиболее распространенная цель виртуального деструктора состоит в том, что клиенты могут правильно delete объекты производных классов через указатели типа Base*.

Однако, если вы сделаете все функции в Base только виртуальные , не pure virtual и предоставите для них реализации (на самом деле выпредоставить), и в то же время вы хотите создать Base абстрактный тип , тогда виртуальный деструктор pure в Base будет only решение:

class Base
{
public:
   virtual void f() {}; //not pure virtual
   virtual ~Base() = 0; //pure - makes Base abstract type!
};

Base::~Base() {} //yes, you have to do this as well.

Base *pBase = new Base(); // error - cannot create instance!

Надеюсь, это поможет.

2 голосов
/ 19 марта 2011

Для меня dtor не является частью интерфейса.Функция fi () будет иметь аналоги на других языках, а не dtor.Аналогично, вы можете написать предварительные и дополнительные условия для fi (), но не для dtor.Это делает его просто бородавкой на C ++, и первый метод - самый удобный способ с ним справиться.

1 голос
/ 19 марта 2011

Хорошо, нашел ссылку и подумал, что я бы упомянул ее в качестве ответа:

Действительно ли встроенные виртуальные функции не имеют смысла?

Я видел компиляторы, которые не генерируют v-таблицу, если вообще не существует не встроенной функции (и определено в одном файле реализации вместо заголовка).Они будут выдавать ошибки, такие как отсутствие vtable-for-class-A или что-то подобное, и вы, как и я, будете в замешательстве.

Действительно, это не соответствует Стандарту, но бывает так, что стоит подуматьпо крайней мере, одна виртуальная функция отсутствует в заголовке (если не только виртуальный деструктор), чтобы компилятор мог создать vtable для класса в этом месте.Я знаю, что это происходит с некоторыми версиями GCC.( Johannes Schaub )

Это немного отличается от вашего второго случая (предлагает фактически убрать функцию из заголовочного файла, чтобы не стать жертвой проблемы gcc), но ядумал, что упомяну это.Причуды gcc могут иногда кусаться.

1 голос
/ 19 марта 2011

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

Если у вас нет причин, по которым вы хотите это форсировать, я бы остановился на первом случае.

...