Search code examples
c++ooppointersdynamicabstract

How can I make a dynamic array of pointers that each point to an abstract base class?


For what I'm working on, I'm making a class that holds a dynamic array of different sorts of pets. I have an abstract class of Animal, from which I have a few derived classes (Cat, Dog, Rabbit, Horse, etc.). I need to be able to add an instance of those derived classes to the end of the dynamic array. In the list object, I have a double pointer (Pet** pets) which is what is supposed to store the list of objects that have Pet as a base class. My thinking is that since Pet is the base class, then each pet pointer should be able to point to an object of type Cat or type Dog, etc.

I have a function in the PetArray class that is supposed to add an object to the end of the list, but I have a couple of issues:

  1. Every time this function is called, all entries in PetArray become the same as the last element I just tried to add.
  2. Later when I try to print info about each element in the array, the program crashes. I have a for loop that is supposed to print information about each element in the array, but my program always crashes on the first iteration of the loop when it's trying to access member data.

I am totally stuck here and am not sure how to fix what's wrong. Any help anybody can provide is greatly appreciated.


Solution

  • Your thinking is correct, but your implementation of add() is not optimal. If nothing else, it is leaking the old pets array. But it is also just coded more complicated than it needs to be.

    It should look more like the following instead (assuming pets and length were initialized properly before add() is called, and that PetArray is managing them correctly per the Rule of 3/5/0, and that your PetArray object is not being corrupted from another bug elsewhere in your code):

    void PetArray::add(Pet *p)
    {
        Pet** temp = new Pet*[length+1];
        for(int i = 0; i < length; ++i)
        {
            temp[i] = pets[i];
        }
        temp[length] = p;
        
        delete[] pets;
        pets = temp;
        ++length;
    }
    

    UPDATE: you are not add()'ing objects to your array correctly. You are creating your derived objects in automatic memory, not in dynamic memory. You are taking pointers to the objects right before they go out of scope and get destroyed, and then you add the now-invalid pointers to your array.

    Pet* p;
    ...
    if(species == "Cat"){
        ...
        Cat c(name, species, age, weight, length);
        p = &c;
    } // <-- c is destroyed here!
    // same goes for the other animal types, too...
    ...
    add(p); // <-- p is invalid here!
    

    This explains both problems you described. You are adding pointers to local memory that gets reused in each loop iteration, and then you crash when trying to access invalid objects.

    You need to new the objects instead, eg:

    Pet* p;
    ...
    if(species == "Cat"){
        ...
        p = new Cat(name, species, age, weight, length);
    }
    // same for the other animal types, too...
    ...
    add(p);