Проблема с наследованием и виртуальными деструкторами в переполнении стека

Итак, у меня есть два класса, один абстрактный, а другой нет.

Абстрактный класс — Iterator, а конкретный класс — LinkedListIterator. Код для обоих в нижней части поста.

У меня проблема с кодом, как показано ниже, я получаю 1 ошибку в LinkedListIterator
на последней строчке деструктора говорят

undefined reference to `Iterator<int>::~Iterator()'

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

Class '[C@800c1' has virtual method 'remove' but non-virtual destructor

Итак, мой вопрос: нужен ли мне виртуальный деструктор в базовом классе абстрактных итераторов? Я читал, что у вас всегда должен быть один, но в этом случае деструктор в LinkedListIterator просто устанавливает значения, он ничего не освобождает …

Спасибо!

Код итератора:

template<class T>
class Iterator {

public:
//~Constructors/Destructors------------//
/*
* Destroys necessary resources.
*/
virtual ~Iterator() = 0;

//~Methods-------------------//
/*
* Informs the user whether there are more elements to be iterated
* over in a List.
*
* @return true if there are more elements to iterate over, false otherwise.
*/
virtual bool hasNext() = 0;

/*
* Gets the next element to iterate over.
*
* @return the next element in the iteration.
*/
virtual T next() = 0;

/*
* Adds an element to the List being iterated over.
*
* @param element the element to add.
* @return true if successful, false otherwise.
*/
virtual bool add(T element) = 0;

/*
* Removes the element last returned by next from
* the List being iterated over.
*
* @return true if successful, false otherwise.
*/
virtual bool remove() = 0;
};

Соответствующий код LinkedListIterator (это длинный класс):

template<class T>
class LinkedListIterator : public Iterator<T> {

private:
//~Data Fields---------------------------------//
/*
* Pointer to the node that the iterator is currently at.
*/
Node<T>* current;
/*
* Pointer to the LinkedList being iterated through.
*/
LinkedList<T>* list;
/*
* Boolean value indicating whether next has been called since
* the last remove operation.
*/
bool nextCalled;

public:
//~Constructors/Destructors------------------//
/*
* Constructor for LinkedListIterator, takes in a pointer to a Node
* to initialize current to point to (intended to be the head of the
* the LinkedList).
*
* @param theList pointer to the LinkedList being iterated through.
*/
LinkedListIterator(LinkedList<T>* theList) {

current = theList->head;
list = theList;
nextCalled = false;
}

/*
* Destructor, resets pointer values to 0.
*/
~LinkedListIterator() {

current = 0;
list = 0;
}

0

Решение

Другие ответили, как решить ошибку, которую вы видите, но ваш вопрос

Нужен ли виртуальный деструктор в базовом классе абстрактных Итераторов?

не было ответа.

Ответ зависит от того, как вы (и другие пользователи) намереваетесь использовать эти классы. Нет ничего плохого в том, чтобы не иметь virtual деструктор и все будет работать правильно до тех пор кто-то решает delete экземпляр LinkedListIterator через Iterator указатель. Например:

Iterator<int> *iter = new LinkedListIterator<int>(...);
delete iter; // undefined behavior if Iterator destructor is not virtual

Но поскольку вы реализуете класс итераторов, шансы на то, что кто-то динамически выделит экземпляр, не говоря уже о попытке его полиморфного удаления, должны быть минимальными. Однако, поскольку у вас уже есть другие виртуальные функции, я не могу думать о недостатке объявления деструктора virtual или.

2

Другие решения

Ваш базовый класс должен иметь virtual деструктор, но не чистый virtual деструктор (*).

Чистые виртуальные функции (то есть функции, помеченные как virtual и с = 0 суффикс добавляется к их подписи) не имеют реализации. Однако деструктор базового класса всегда должен вызываться деструктором подкласса, и вы должны предоставить для него определение (возможно, пустое):

template<class T>
class Iterator {

public:
//~Constructors/Destructors------------//
/*
* Destroys necessary resources.
*/
virtual ~Iterator() { }
...

Также см этот вопрос&А на StackOverflow для связанной информации.

(*) Как уже упоминалось в связанном Q&О, возможно иметь чистый виртуальный деструктор (для которого определение все еще необходимо), но я не считаю это особенно хорошей практикой программирования.

6

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

virtual ~Iterator() { }

должен это исправить.

PS: чисто к вашему сведению есть список ссылок std, std :: list

3

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

Просто добавьте пустой деструктор для Iterator; вам не нужно терять «чистый» деструктор (хотя это не имеет особого смысла, поскольку у вас уже есть другие чисто виртуальные методы).

3