Чистое определение виртуального деструктора внутри класса дает ошибку компиляции - PullRequest
13 голосов
/ 19 ноября 2011

У pure virtual destructor в базовом классе должно быть определение. В противном случае компилятор сгенерирует вызов деструктора базового класса из деструктора производного класса во время компоновки и вызовет ошибку ссылки.

Я попытался определить чистый виртуальный деструктор внутри базового класса, как показано ниже:

class base
{
   public:
      base()
      {
         cout << "constructor in base class\n";
      }

      virtual ~base()=0
      {}
};

Это дало ошибку компиляции:

ошибка: чистый спецификатор для определения функции

Затем я попытался определить функцию вне базового класса, как показано ниже:

class base
{
   public:
      base()
      {
         cout << "constructor in base class\n";
      }

      virtual ~base()=0;
};

base::~base()
{

}

Это устраняет ошибку компиляции и ведет себя как я понимаю.

Но мой вопрос заключается в том, как определение чистого виртуального деструктора вне базового класса устраняет ошибку компиляции?

Ответы [ 5 ]

11 голосов
/ 19 ноября 2011

Ваш второй пример верен.

Многие другие ответы предполагают, что иметь чисто виртуальную функцию с реализацией по умолчанию недопустимо, однако это неверно.

В случае чистого виртуального деструктора у вас должно быть определение (см. ссылку в ответе xmoex).

Это правда, что:

§10.4 / 2 объявление функции не может предоставить как чисто спецификатор и определение

Однако, как вы заметили, можно предоставить определение вне декларации.

7 голосов
/ 19 ноября 2011

Я посмотрел на этой странице:

http://www.gotw.ca/gotw/031.htm

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

5 голосов
/ 19 ноября 2011

Недопустимый синтаксис для записи:

virtual ~base()=0
{}

Если вы хотите предоставить реализацию чисто виртуальной функции-члена, вы должны сделать это вне класса.В большинстве случаев вам не следует этого делать, поскольку чистые виртуальные функции никогда не должны вызываться.Однако возможно определить реализацию для чисто виртуальных функций.

Фактически, чистый виртуальный деструктор должен иметь реализацию.Это связано с тем, что деструкторы всех базовых классов вызываются при уничтожении объекта независимо от того, является ли деструктор в данном классе чисто виртуальным или нет.

Таким образом, если вы создаете экземпляр любого из классов, полученных из baseтогда в какой-то момент будут вызваны деструкторы всех классов, к которым принадлежит объект, включая деструктор base::~base().Если вы не определите его, компоновщик не найдет требуемый символ и будет жаловаться.

3 голосов
/ 19 ноября 2011

Деструктор является единственным методом, который, даже если он чисто виртуальный, должен иметь реализацию, чтобы класс, в котором он определен, был полезным.Поэтому, в отличие от ответа @ Кирилла, я бы сказал, что чисто виртуальные функции могут иметь реализации.

Несколько не по теме:

struct base {
    virtual void func() = 0;
};

void base::func() { /* default implementation */ }

class derived : public base{
    void func() { base::func(); } // have to explicitly call default implementation.
};
1 голос
/ 19 ноября 2011

Чистые виртуальные методы могут иметь реализации, но они делают базовый класс абстрактным и заставляют производные классы перезаписывать эти методы.

Скажем, у вас есть элемент указателя в базовом классе.Вы хотите удалить его в деструкторе, но также сделать класс абстрактным - так что вы реализуете его в чисто виртуальном деструкторе.

Это деталь реализации - тот факт, что деструктор реализован, не должен быть виден снаружи.

...