101010110101
101010110101

Reputation: 2000

How to create a dynamic array of an Abstract class?

Lets say I have an abstract class Cat that has a few concrete subclasses Wildcat, Housecat, etc.

I want my array to be able to store pointers to a type of cat without knowing which kind it really is.

When I try to dynamically allocate an array of Cat, it doesn't seem to be working.

Cat* catArray = new Cat[200];

Upvotes: 14

Views: 22751

Answers (5)

Kaleb Coberly
Kaleb Coberly

Reputation: 460

Something I did in a similar case was then to loop through the array and point each element to nullptr. That way you can easily check whether you've added a derived class object to a slot or if it's open.

Cat** catArray = new Cat*[200];
for(int i = 0; i < 200; i++){
   catArray[i] = nullptr;
}

for(int i = 0; i < 200; i++){
   if(catArray[i] != nullptr){
      AddRealCat(...);
      break;
   }
}      

I wonder if there's an easier way to do this, to check whether an element in an array of pointers to an abstract class points to an object of a derived class or is just an abstract pointer, without setting the element to nullptr. Like, is there a bool IsObject(ObjectType* ptr) or something in the standard library?

And, I wonder if setting each element to nullptr poses any potential problems, other than the computing cost of looping through the array and setting them to nullptr.

I posted this as an independent question (Array of Pointers to an Abstract Class: to nullptr or not to nullptr (C++)), but I thought it might be relevant here since this post is the closest to my question that I found when searching.

Upvotes: 0

Jive Dadson
Jive Dadson

Reputation: 17026

You cannot round up the cats in fixed size cages, because the compiler has no way of knowing how big the cats will be, nor (metaphor failure) how to initialize them. You are going need to do something like initialize the array to null cat-pointers or something, and herd them later.

Upvotes: 4

Jasmeet
Jasmeet

Reputation: 2352

By creating an aray of pointers to Cat, as in

 Cat** catArray = new Cat*[200];

Now you can put your WildCat, HouseCat etc instances at various locations in the array for example

 catArray[0] = new WildCat();
 catArray[1] = new HouseCat();
 catArray[0]->catchMice(); 
 catArray[1]->catchMice();

Couple of caveats, when done
a) Don't forget deleting the instances allocated in catArray as in delete catArray[0] etc.
b) Don't forget to delete the catArray itself using

 delete [] catArray;

You should also consider using vector to automate b) for you

Upvotes: 22

mmr
mmr

Reputation: 14919

You cannot directly instantiate an instance of an abstract class, but must instead instantiate an instance of a fully implemented subclass.

So this is legal:

Housecat* theCats = new Housecat[200];

and then you can access each cat through the Cat interface

bool catsMeow = ((Cat*)(&theCats[0]))->CanMeow();

But the compiler has no way of knowing how to instantiate an abstract class; in fact, the very fact that it's abstract means that it cannot be directly instantiated.

Why do this? Because Cat will have an abstract method

bool CanMeow() = 0;

That all inherited cats must implement. Then you can ask if it can meow, with the chance that an instance of Lion will return false.

Upvotes: 0

James McNellis
James McNellis

Reputation: 355069

You would need to create an array of pointers to Cat:

Cat** catArray = new Cat*[200];

Even if the base class Cat was concrete, you would still run headlong into object slicing if you created an array of Cat.

Note that you should probably use a std::vector instead of an array, and should probably use smart pointers to ensure your code is exception safe.

Upvotes: 7

Related Questions