0

I'd like to define an abstract base class and then pass an array of that type (obviously full of instances of a derived class) as a function parameter, but the compiler is yelling at me. Any ideas?

For example ("Testable" is abstract, "Vecteur" is concrete):

void Testeur::commencerTest(Testable testables[], int nTestables, string titre) {
    cout << "\n" << titre << "\n";
    for (int i=0; i < nTestables; i++) {
        testables[i].afficher();
    }
}

// in main function:
Vecteur v1 = Vecteur(1,2,3);
Vecteur v2 = Vecteur(4,5,6);
Vecteur vecteurs[] = { v1, v2 };
int nVecteurs = 2;

this->commencerTest(vecteurs, nVecteurs, "Some text");

The compiler says invalid abstract type ‘std::Testable’ for ‘testables’ at the first line of the above code.

How can I pass an abstract-typed array as a function param?

Paul Hiemstra
  • 59,984
  • 12
  • 142
  • 149
weberc2
  • 7,423
  • 4
  • 41
  • 57

3 Answers3

5

The short answer is: you can't. Arrays are not polymorphic in C++; this is for good reason - see e.g. What is object slicing?. Remember that to do e.g. arr[i], the compiler needs to know how big each element is (to calculate the address offset); this calculation will be wrong, in general, for derived types.

You consider using a function template, or perhaps an array/container of (smart) pointers.

Community
  • 1
  • 1
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
1

You can't have an array of objects and then cast it to array of other objects. Think of it, if Vecteur sizeof is 16 and Testable sizeof is 4, how could this even work?

What you want is an array of pointers to objects.

void commencerTest(Testable* testables[], int nTestables)
{
    for (int i=0; i < nTestables; i++)
        testables[i]->afficher();
}

int main()
{
    Testable* vect[10];

    for(int i=0; i<10; i++)
        vect[i] = new Vecteur();

    commencerTest(vect, 10);
}
Agent_L
  • 4,960
  • 28
  • 30
  • Your code throws this error: `base operand of ‘->’ has non-pointer type ‘std::Testable` at the `testables[i]->afficher();` line. – weberc2 Apr 25 '12 at 16:40
  • @weberc2 It works for me: http://codepad.org/pNWtj8yV The error has to be elsewhere. As others pointed, don't declare own types inside std::. – Agent_L Apr 25 '12 at 17:00
0

Try this:

template <typename Type>
  void Testeur::commencerTest(Type *testables, int nTestables, string titre) {

The code will eventually complain about not knowing the size of the array. Polymorphism will work through a pointer but not an array as others have noted.

As another possibility, you can use compile-time polymorphism for both type and number for static arrays:

template<typename Type, size_t Num>
  void Testeur::commencerTest(Type (&testables)[Num], string titre) {

Also, the standard library containers are a good solution.

emsr
  • 15,539
  • 6
  • 49
  • 62
  • 1
    This is completly wrong. Trying to stride an array of Vecteur with sizeof(Testable) will give wrong pointers after first one. http://codepad.org/ysaJnd5T – Agent_L Apr 25 '12 at 12:35
  • Right. This is what happens for trying to do 8 things at once ;-) Thanks for the link to codepad (I've used Ideone - and should have with this post). +1. I'll edit with something that works - template the type. – emsr Apr 25 '12 at 13:29