Sign in to follow this  

Polymorphism and pointer arrays in c++

This topic is 1965 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So, I haven't been able to find a good explanation on this.

I want a dynamic size to my array, basically then I read in the level it tells me how many objects I need so I do the following:

MObject *objects = new MObject[num_of_obj];

after I find out how many I need through the text file I created that's reading in the level, I find out what KIND of MObjects they are so one of them is a SpeedBoost obj (inherits MOBject)

*(object+obj_counter)= SpeedBoost(args...);

for simplicity sake objcounter is 0 for now

MObject has
virtual Draw();

SpeedBoost has
Draw();

when I attempt to run through a list of objects and call:

objects[loop1].Draw();

the SpeedBoost::Draw() is never called
only the MObject::Draw() is called.

I need it to call the implementation of the Draw for the class that it is not the base class draw.

I'm know that implementing a linked list would probably work but that's added complexity for something that an array should hopefully be able to do.

Share this post


Link to post
Share on other sites
[quote name='Vero' timestamp='1343333709' post='4963420'][code]*(object+obj_counter)= SpeedBoost(args...);[/code][/quote]

You are [url=http://en.wikipedia.org/wiki/Object_slicing]slicing[/url] your [tt]SpeedBoost[/tt] here. The temporary [tt]SpeedBoost[/tt] you create here is truncated to a [tt]MObject[/tt] so it can fit inside the [tt]MObject[/tt] array. Try the following code:

[code]
// Create
MObject** objects = new MObject*[num_of_obj];

// Use
objects[0] = new SpeedBoost( ... );
objects[1] = new OtherObject( ... );

// Cleanup
for ( ... )
delete objects[idx];
delete[] objects;
[/code]

Share this post


Link to post
Share on other sites
Ok that worked perfectly, and I understand now what slicing is but I don't quite understand why the solution works.

lets see if I can figure it out. MObject** is a pointer to an array of pointers so it's allocates a slot to each pointer but doesn't allocate them a type yet? so now that they have not be allocated a type we can use new to allocate them to the correct class?

Share this post


Link to post
Share on other sites
[quote name='Vero' timestamp='1343335764' post='4963431']MObject** is a pointer to an array of pointers so it's allocates a slot to each pointer but doesn't allocate them a type yet? so now that they have not be allocated a type we can use new to allocate them to the correct class?[/quote]

Yes. Keep in mind that [tt]MObject[/tt] is an [tt]MObject[/tt] itself, while a [tt]MObject*[/tt] (or [tt]MOjbect&[/tt]) is the [tt]MObject[/tt] interface of an [tt]MObject[/tt] or one of its derived types.

Share this post


Link to post
Share on other sites
[quote name='dimitri.adamou' timestamp='1343340703' post='4963446']
I may be wrong - you need to specify that SpeedBoost is also a virtual function. Thats why its never called
[/quote]
I could be wrong too but alternatively if there's no Mobject draw() method as such he could make it pure virtual by appending =0

Share this post


Link to post
Share on other sites
A slightly more idiomatic C++ solution:

[code]class Object
{
public:
virtual void Display() const = 0;
};

class IntObject : public Object
{
public:
explicit IntObject(int value)
: MyValue(value)
{ }

virtual void Display() const
{
std::cout << "Integer object: " << MyValue << std::endl;
}

private:
int MyValue;
};

class StringObject : public Object
{
public:
explicit StringObject(const std::string& value)
: MyValue(value)
{ }

virtual void Display() const
{
std::cout << "String object: " << MyValue << std::endl;
}

private:
std::string MyValue;
};

int main()
{
// Also try boost::shared_ptr or boost::scoped_ptr if you're on an outdated compiler
typedef std::vector<std::unique_ptr<Object>> ObjectContainer;
ObjectContainer objects;

// Create us some objects!
objects.push_back(new IntObject(1));
objects.push_back(new StringObject("test"));

// Do stuff the C++11 way
std::for_each(
std::begin(objects),
std::end(objects),
[](const std::unique_ptr<Object>& obj)
{
obj->Display();
}
);

// Alternately, the C++98 way
for(ObjectContainer::const_iterator iter = objects.begin(), end = objects.end(); iter != end; ++iter)
{
(*iter)->Display();
}

// Note: no need to explicitly delete anything!
}[/code]


My C++11 is still getting into shape, so feel free to nitpick on that bit :-) Also, [i]please[/i] feel free to ask any questions this code might raise!


(Note also that this could be done with templates instead of manually creating an IntObject and StringObject, but that seems a bit excessive in the context of the OP's question.) Edited by ApochPiQ
Accidentally a void.

Share this post


Link to post
Share on other sites
[quote name='ApochPiQ' timestamp='1343354399' post='4963482'][code]
// Do stuff the C++11 way
std::for_each(
std::begin(objects),
std::end(objects),
[](const std::unique_ptr& obj)
{
obj->Display();
}
);
[/code][/quote]
I can't help but feel it's clearer to write it this way (still C++11).
[code]
for (const auto& obj: objects)
{
obj->Display();
}
[/code]

Share this post


Link to post
Share on other sites
ApochPiQ:

I think you meant

[CODE]
objects.push_back(std::unique_ptr<Object>(new IntObject(1)));
objects.push_back(std::unique_ptr<Object>(new StringObject("Test")));
[/CODE]

Or maybe not, if your compiler doesn't force you to be so verbose. VS10 does.

Also you forgot to give Object a virtual dtor.

Share this post


Link to post
Share on other sites

This topic is 1965 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this