удалить абстрактный не виртуальный dtor С++

У меня есть интерфейс, представляющий абстрактный тип данных «Сумка». Чтобы реализовать этот абстрактный тип данных, я использовал реализацию на основе массива и связанную.

Здесь определение класса

редактировать Как вы указали, я добавил виртуальный деструктор в свой базовый класс

template<class ItemType>
class BagInterface{

public:
    virtual int getCurrentSize() const = 0;
    
    virtual bool isEmpty() const = 0;
    
    virtual bool add(const ItemType& newEntry) = 0;
    
    virtual bool remove(const ItemType& anEntry) = 0;
    
    virtual int getFrequencyOf(const ItemType& anEntry) const = 0;
    
    virtual bool contains (const ItemType& anEntry) const = 0;

    virtual void clear() = 0;
    
    virtual vector<ItemType> toVector() const = 0;

    virtual ~BagInterface() = default;
};


#endif /* BagInterface_hpp */

И мои 2 производных класса реализуют эти методы на своем пути.

В моей реализации на основе ссылок используется виртуальный деструктор, потому что, в отличие от реализации на основе массива, он динамически выделяет память, и в конечном итоге он должен удалить экземпляр с помощью ключевого слова «удалить», чтобы избежать утечек памяти.

деструктор связанного мешка

template<class ItemType>
LinkedBag<ItemType>::~LinkedBag(){
    clear(); // Clears bag's content.
}

деструктор массива

template<class ItemType>
ArrayBag<ItemType>::~ArrayBag(){
    clear();
}

После всех проблем с реализацией я хотел проверить свои операции с ADT.

Я создал функцию, которая принимает указатель в качестве входных данных для представления сумки.

void bagTester(BagInterface<int>* bagPtr){
   // do some test }

в моей основной функции, после того, как я закончил свой тест, я хотел удалить свой bagPtr, потому что я закончил с ним, поэтому пришло время его удалить.

  int main(){
     BagInterface<int>* bagPtr = nullptr;
    
     char userChoice;
     cin>> userChoice;
    
     if(userChoice == 'A'){
     bagPtr = new ArrayBag<int>(); // Array based implementation 
    }else if(userChoice == 'L'){
     bagPtr = new LinkedBag<int>(); // Link bases implementation
    }

    bagTester(bagPtr); // test my bag
    
    delete bagPtr; // and now i'm finished with test let's delete the pointer
    bagPtr = nullptr; // deallocate
}

**В этом месте возникает моя ошибка, компилятор выдает предупреждение -› **

In file included from main.cpp:2:
In file included from ./LinkedBag.hpp:5:
./BagInterface.hpp:36:31: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions]
    virtual ~BagInterface() = default;
                              ^
In file included from main.cpp:4:
./ArrayBag.hpp:28:5: error: exception specification of overriding function is more lax than base version
    ~ArrayBag();
    ^
main.cpp:48:22: note: in instantiation of template class 'ArrayBag<int>' requested here
        bagPtr = new ArrayBag<int>();
                     ^
./BagInterface.hpp:36:13: note: overridden virtual function is here
    virtual ~BagInterface() = default;
            ^
In file included from main.cpp:2:
./LinkedBag.hpp:25:1: error: exception specification of overriding function is more lax than base version
~LinkedBag();
^
main.cpp:52:22: note: in instantiation of template class 'LinkedBag<int>' requested here
        bagPtr = new LinkedBag<int>();
                     ^
./BagInterface.hpp:36:13: note: overridden virtual function is here
    virtual ~BagInterface() = default;
            ^
1 warning and 2 errors generated.

Я проверил эту связанную тему - › Подавить предупреждение об удалении невиртуального dtor при использовании защищенного невиртуального деструктора

И я попробовал одно из предложений, которое было указано там, а именно:

Правило № 4: Деструктор базового класса должен быть либо общедоступным и виртуальным, либо защищенным и невиртуальным.

А также попытался добавить виртуальный деструктор в BagInterface, но это не сработало (редактирование: я узнал, что должен добавить виртуальный деструктор :))

Я не понимаю проблемы, потому что оба производных класса имеют свой собственный деструктор, у arrayBag есть деструктор по умолчанию, у linkedBag есть виртуальный деструктор.

Итак, как я могу избежать предупреждения?


person Rutkay Karabulak    schedule 15.10.2020    source источник
comment
пытался добавить в BagInterface виртуальный деструктор, но это не сработало Давайте сделаем это нашей отправной точкой. Вы добавляете в BagInterface виртуальный деструктор, потому что отсутствие виртуального деструктора — это неправильно. Так что все, что было до того, как вы добавили виртуальный деструктор, неверно. Теперь, когда у вас есть виртуальный деструктор, опишите свою проблему.   -  person n. 1.8e9-where's-my-share m.    schedule 16.10.2020
comment
вы понимаете, что прямо сейчас у вас происходит утечка памяти, потому что деструктор реализации на основе ссылок не вызывается через ваш delete bagPtr?   -  person user    schedule 16.10.2020
comment
@n.'местоимения'm. Но без добавления виртуального деструктора в BagInterface, по крайней мере, я могу скомпилировать с предупреждением, но когда я добавляю виртуальный деструктор в BagInterface, я даже не могу скомпилировать, это дает кучу ошибок...   -  person Rutkay Karabulak    schedule 16.10.2020
comment
Давай попытаемся снова. Не иметь виртуального деструктора неправильно. Наличие виртуального деструктора правильно. Однако наличие одного только виртуального деструктора не гарантирует правильности. У вас могут быть другие проблемы с вашим кодом. Однако вы не делитесь своими ошибками, поэтому мы не можем сказать, что это за неправильные вещи. Если вы хотите получить ответ на свой вопрос, вы должны опубликовать свои фактические ошибки, напечатанные компилятором. Это не сработало, никакой полезной информации. Мы можем предположить, что это не сработало. Возможно, иначе вас бы здесь не было.   -  person n. 1.8e9-where's-my-share m.    schedule 16.10.2020
comment
Для ясности: если программа удаляет объект производного типа через указатель на базу и база не имеет виртуального деструктора, поведение программы не определено.   -  person Pete Becker    schedule 16.10.2020
comment
Добавление виртуального деструктора к BagInterface — правильное решение. Не могли бы вы отредактировать свой вопрос, чтобы показать этот код и спросить об ошибках, которые он генерирует? (Я бы даже начал с этого и переместил большую часть контекста после вопроса. Заинтересуйте людей сразу, вместо того, чтобы задавать им вопрос, идет ли этот вопрос куда-то?)   -  person JaMiT    schedule 16.10.2020
comment
Я собираюсь отредактировать свой вопрос в соответствии с вашими предложениями, дайте мне минуту ...   -  person Rutkay Karabulak    schedule 16.10.2020
comment
Одна вещь, которую вы обнаружите в программировании, это то, что иногда исправление ошибки выявляет больше ошибок. Не думайте, что код, который компилируется, ближе к правильному, чем код, который не компилируется. Очень легко написать код, который компилируется и является логически неправильным. Кроме того, иногда вы можете добавить столь необходимую точку с запятой или закрывающую фигурную скобку и увидеть, как список ошибок увеличивается от одной ошибки до сотен, потому что теперь компилятор может интерпретировать больше кода и отображать комментарии о его правильности. Делайте то, что правильно, а затем разбирайтесь со всеми обнаруженными новыми ошибками.   -  person user4581301    schedule 16.10.2020
comment
@n.'местоимения'm. во-первых, я новичок на этой платформе, и вы правы, я должен был быть более ясным, «это не сработало» - не очень хорошее объяснение. Спасибо за все ваши советы, я постараюсь улучшить себя, когда объясню свой вопрос. Теперь я отредактировал свой вопрос в соответствии с вашими предложениями...   -  person Rutkay Karabulak    schedule 16.10.2020
comment
Ваш компилятор настолько стар, что по умолчанию используется стандарт С++ 2003. Вы можете добавить флаг -std=c++11 ко всем вашим командам компиляции. Это избавит от ошибок? А еще лучше обновиться до современной версии.   -  person n. 1.8e9-where's-my-share m.    schedule 16.10.2020
comment
@n.'местоимения'm. теперь это исправлено ... Omg, во-первых, большое спасибо всем, во-вторых, я такой новичок, я чувствую, что, вероятно, я подействовал вам на нервы. Но спасибо, я многому научился из этого вопроса...   -  person Rutkay Karabulak    schedule 16.10.2020


Ответы (1)


Прямо сейчас, когда вы запускаете этот код:

delete bagPtr;

деструктор из реализации на основе ссылок не вызывается.

template<class ItemType>
class BagInterface{

public:
.....
virtual ~BagInterface() = default;
};

Вам нужен этот деструктор, если вы собираетесь удалить класс, производный от BagInterface, через указатель на BagInterface (или если sharedpointer<BagInterface>, указывающий на производный класс от BagInterface, выходит за рамки).

В моей реализации на основе ссылок используется виртуальный деструктор, потому что, в отличие от реализации на основе массива, он динамически выделяет память, и в конечном итоге он должен удалить экземпляр с помощью ключевого слова «удалить», чтобы избежать утечек памяти.

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

Удаление объекта с помощью указателя на базу вызывает неопределенное поведение, если только деструктор в базовом классе не является виртуальным. источник здесь

person user    schedule 15.10.2020
comment
Это хуже, чем утечка памяти. Поведение программы не определено. - person Pete Becker; 16.10.2020
comment
@PeteBecker Я этого не знал, спасибо. - person user; 16.10.2020
comment
@PeteBecker большое спасибо... - person Rutkay Karabulak; 16.10.2020
comment
@user Действительно ценю... - person Rutkay Karabulak; 16.10.2020