I created a class that was a base class for two subclasses, let's say subclass1 and subclass 2. I want to create a dynamic array that can contain BOTH kinds of subclasses; so I tried creating a dynamic array of the base class.
That worked, I could do things like
but trouble arises when I try calling a function included in both subclasses. My call looks something like thisCode:base_array[0] = subclass1("your mom",28); base_array[1] = subclass2("your dad",29);
I want it to call the subfunction based on whether or not base_array[0] is a base_class, a subclass1, or a subclass2, but it always calls the base_class::subfunction() one, which I never want used. How do I get it to work so that I can have a dynamic array with both kinds of subclasses and call the subfunction in the way described?Code:void blahblahblah() { base_array[0].subfunction(); }
Oh and the subfunction is virtual
If you know what type it really is, you can use static_cast or dynamic_cast to get at the correct version of the method.
I don't.. I could use some sort of flag, but that seems annoying.. shouldn't there be a way to do it polymorphically? and in the case that I do use what you mentioned... what are static_cast and dynamic_cast?
That's the expected behavior.
When you assign the subclass object to the dyna-array that's expected to hold base class object, the assignment operator is called which doesnot copy the subclass object bit by bit. Instead, the assignment operator you define for base class or the assignemnt operator composed by the compiler is execute. All boiled down, the vptr is pointed the bass class virtual table. So literally they are all base class objects.
Your design is essentially problematic. To make your dynamic array to be able to hold all base class, subcalss1 , subclass2 objects, the three type has to has the same size. Or any clss derived from base calss are not expected to add new member variables.
Anyway, let's say this is what you want, It's achievable by some sort of hack --- copy it bit by bit.
try with the above code, you may get the behaviour you expected. I did not test the code, so you may need some extra work to make it work. Note it's not the right way of programming c++, but I belive it serves to make you understand the underlying mechanism of multi-morphism more deeply.Code:class Base{ public: Base():data(0){} Base& operator=(const Base& rhs){ memcpy(this, &rhs, sizeof(*this)); } virtual void whoAmI(){ std::cout<<"I am a base object and my data is "<<data<<std::endl; } protected: int data; }; class Subclass1: public Base { public: Subclass1(){ data=1; } void whoAmI()const{ std::cout<<"I am a Subclass1 object, and my data is "<<data <<std::endl; } }; ...
Adding to that... Because your pointers are to the base class, C++ treats all objects in the array as base class objects. It doesn't have a way to know otherwise. There are a lot of ways around this, but they all come down to a flag system to know what the object really is, and using casting (explicitly indicating that an object is something other than it appears) to get it treated as what it is. If you Google both casts, you should get plenty of examples on using them.
alright I hoped from the beginning that there would be another way, but I guess not. Thanks all
generally you shoudl store pointer to objects in the array. That's the preferred way of maintaining polymorphism.
flag and dynamic_cast or static cast or reinterpret_cast would not do the magic because the underlying objects have indeed been changed to Base class objects.
If speed, memory efficency are really such a big concern and you pretty much sure all the subclasses would not have a bigger size. (ie: sizeof(Base)=sizeof(Each subclasses),
you can do it with the way I mentioned above, only you also need to define a copy constructor for Base to implement the bit by bit copy.
Here's what happened in your program:
array[0]=subclass1object;
The subclass1object before assignment:
+------+
| data |
|vptr ---> subclass1 vtable
+------+
After assignment, array[0] becomes
+------+
| data |
|vptr ---> Base vtable
+------+
so dynamic_cast would not work even if you flag it as a Subclass1 object and
above code would fail because dynamic_cast would fail and return NULL pointer.Code:if( marked as Subcalss1Object){ Subclass1 * p=dynamic_cast<Sublclass1*>(&array[0]); if (p!=NULL) p->VirtualFunctionCall(); }
There is a really ugly way to do mark and call (essentially your own way of polymorphism).
Esstentially you circumvent the vtable and call the functions directly. If that's the way you are going to implemented, why bother define them as virtual at the first place.Code:switch(object.flag) { case Subclass1Flag: Subclass *p=reinterpret_cast<Subclass1*>(&object); p->Subcalss1::VirtualFunctionCall(); ...
Ugly design, and waste memory space for the flags, a move I would definitely avoid.
I got it working by checking the flag inside the class and then casting it. Works fine. Thanks
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks