Polymorphism & Pointers to arrays [duplicate]
Asked Answered
A

3

7

I have a class A:

class A
{
    public:
        virtual double getValue() = 0;
}

And a class B:

class B : public A
{
    public:
        virtual double getValue() { return 0.0; }
}

And then in main() I do:

A * var;
var = new B[100];
std::cout << var[0].getValue(); //This works fine
std::cout << var[1].getValue(); //This, or any other index besides 0, causes the program to quit

If instead I do:

B * var;
var = new B[100];
std::cout << var[0].getValue(); //This works fine
std::cout << var[1].getValue(); //Everything else works fine too

Everything compiles fine, but it seems as though there is something wrong with my polymorphism perhaps? I'm puzzled.

Aureole answered 11/9, 2009 at 16:5 Comment(0)
L
12

You can't treat arrays polymorphically, so while new B[100] creates an array of B objects and returns a pointer to the array - or equivalently the first element of the array - and while it is valid to assign this pointer to a pointer to a base class, it is not valid to treat this as a pointer into an array of A objects.

The principal reason that you can't is that (typically) derived objects are a different size to their base classes, so attempting to access the array as an array of base class objects will not use the correct offset to get a pointer to the next base class subobject of the next member of the derived class array.

Lattice answered 11/9, 2009 at 16:13 Comment(13)
@Charles I'm assuming if he changes his array to A ** var then this restriction won't apply (and properly initialises it by new'ing all 100 items)Shrew
Ahh, I see. So I'd want to create an array of 100 pointers to A instead, right?Aureole
@Glen: Not quite sure what your driving at. You'd have an array of pointers and not an array of objects. Because pointers don't derive from other pointers the problem doesn't arise.Lattice
@Charles. If he had an array of pointers to A, then he could do var[i] = new B(); Then call var[i]->getValue() and B::getValue() would be called correctlyShrew
@Stewart: What are you ultimately trying to achieve? If you have an array of pointers to dynamically created objects then you have a lot of memory management issues. What's wrong with keeping an array of B objects and just retaining the correct type?Lattice
@Glen: Well, yes, it works but now he has to manually allocate 100 objects and, at some point, deallocate them. Personally, I'd go for the array of objects (or more likely I'd use a std::vector<B>).Lattice
Ultimately I'll have a rectangular matrix of objects deriving from A, which could be of 10 or so different sub-classes, so I define an update() method in A, and each subclass updates itself in a different way.Aureole
@Charles, sure, but if he wants to put B, C, D and E objects into the array then he's gonna have to use pointers. (and I see by his latest comment that this is what he wants)Shrew
@Glen: With the use of new B[100] this seemed unlikely, but it looks like I was mislead.Lattice
I apologise, I didn't mean to mislead; the matrix will be predominantly of one type, with smaller numbers of various other sub-classes. Is there any advantage to your suggestion with vectors over just an array of pointers to A, that I can then delete and replace with a new B?Aureole
If you have boost available, consider using a std::vector< boost::ptr_vector< A > >. If you avoid having to manually delete your dynamically created objects then you won't have any leaks.Lattice
@Charles, sorry for the confusion. + I really wish I had boost here. Stuff like that boost::ptr_vector looks really useful!Shrew
Okay, thanks. But just to confirm, what I most recently said is the correct basic way to handle this?Aureole
P
6

There is no problem with the polymrphism but with the way you are dealing with memory. The [] operator will advance you through the array by the sizeof(A) bytes in the first case and the sizeof(B) bytes in the second case. Because the objects are of type B the A* is not pointing to the correct location in memory.

Here is another way of looking at it

char * var;
var = (char*) new B[100];
std::cout << ((A*)var[0]).getValue(); //This works fine
std::cout << ((A*)var[1]).getValue(); //This will fail
std::cout << ((A*)var[sizeof(B)]).getValue(); // should work
Pap answered 11/9, 2009 at 16:20 Comment(0)
D
-1

You didn't allocate the objects in the array:

for (int i=0;i<100;i++)
  var[i] = new B;

(although I may be mixing up C++ and C#)

Dairyman answered 11/9, 2009 at 16:9 Comment(7)
Don't think that's correct. It's an array of B objects, not an array of pointers to B objects.Shrew
var is a pointer variable and not a pointer to a pointer so var[i] = new B isn't valid (unless there's an unusually defined assignment operator taking a pointer).Lattice
That's incorrect. char * c = new char[100]; for(...) c[i] = foo; worksLemma
No, you got it right. Most OO languages (that I've used) work the same way for creating arrays of objects.Wormy
That would require var to be an array of pointers. B ** var;Coldblooded
@Paul Nathan: ... only if foo is a char and not a char* . (To complete the analogy with the posted code.)Lattice
No, he's allocating an array of objects; not an array of pointers to objects.Florina

© 2022 - 2024 — McMap. All rights reserved.