Search code examples
c++pointersabstract-classabstract-data-type

Deleting derived class through base class pointer c++


I have an interface that represent ADT 'Bag'. To implement that abstract data type I used Array based and Linked based implementation.

Here the definition of class

edit As you indicated, i've added virtual destructor to my Base class

template<class ItemType>
class BagInterface{

public:
    ... some methods

   ~BagInterface();
};


#endif /* BagInterface_hpp */

And my 2 derived class implement these methods on their way.

My link based implementation is using virtual destructor because unlike array based implementation it's dynamically allocating memory and eventually it has to delete instance by using 'delete' keyword due to avoid from memory leaks.

destructor of linked bag

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

destructor of arraybag

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

I've created a function that takes a pointer as a input to represent bag in order to test my implementations.

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

I'd like to delete my derived class through base class pointers in the following.

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

    bagTester(bagPtr); // test my bag
    
    delete bagPtr; // and now i'm finished with test let's delete the object
    bagPtr = nullptr; // to avoid dangling pointers
}

In that point my error is occurring, compiler gives a warning ->

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.

So, how can I avoid from the warning?


Solution

  • Right now, when you run this code :

    delete bagPtr;
    

    the destructor from the link based implementation isn't called.

    template<class ItemType>
    class BagInterface{
    
    public:
    .....
    virtual ~BagInterface() = default;
    };
    

    You need this destructor if you are going to delete a class derived from BagInterface through a pointer to BagInterface (or if a sharedpointer<BagInterface> pointing to a derived class from BagInterface goes out of scope).

    My link based implementation is using virtual destructor because unlike array based implementation it's dynamically allocating memory and eventually it has to delete instance by using 'delete' keyword due to avoid from memory leaks.

    This is why you need a virtual destructor in your base class : if you don't have one, when you delete a derived class through a pointer of the base class, you get undefined behaviour.

    Deleting an object through pointer to base invokes undefined behavior unless the destructor in the base class is virtual. source here