I have a Hallway class that is made up of a vector of Rooms. I have two types of Rooms - Bathrooms and Bedrooms. The toString() function in Room is a virtual function that I want to be overloaded by Bathroom and Bedroom. Whenever I call Hallway's toString() function, I want it to go through and call each Room's toString() function. The problem is that instead of calling Bathroom's or Bedroom's toString(), it calls Room's toString(). I'm assuming it's because the Hallway is a vector of Room's and not Bathroom's or Bedroom's. But I thought it would call the appropriate virtual function if a Room is a subclass. How can I check what kind of Room each Room is, and call the appropriate toString()? Here is some code if it's needed

I'm assuming it's because the Hallway is a vector of Room's and not Bathroom's or Bedroom's.

Sounds like you have an issue with object slicing when you add the Bedrooms to the vector. Make the container a vector of Room pointers instead of just a vector of Rooms. This will allow the appropriate virtual function to be called.

11-02-2009

Elysia

Polymorphism only works on pointers or references.
Furthermore, when you add a non-pointer to an object, you slice it. Meaning that everything that is not a Room is lost in the conversion to a Room.
So in effect: you need to store pointers allocated with new or some such. You can use smart pointers to avoid memory management.

11-02-2009

Daved

The problem appears to be that your Hallway vector holds Room objects, not pointers. Since it holds Room objects, every time you add a Bathroom or Bedroom to the hallway, you slice off the derived-ness of the class and only the base class data is saved.

Dynamic polymorphism, which is what you're correctly trying to use, only works on pointers or references. You can't store references in vectors or arrays, so you have to store pointers. Make Hallway store a vector<Room*> instead.

Doing this brings up some other interesting challenges. The most important is, who "owns" the Rooms? It probably doesn't make sense for a Hallway to own the rooms it is connected to, so you'll have to identify something else that keeps the master pointer to each room and deletes it when it is all done.

There are more advanced tools to help with this, including shared_ptr. If you can use that, I'd recommend it, but often that is not allowed for assignments since you'd have to get another library like boost. If you can't, then you just have to pay extra attention to who maintains the pointer and when it gets deleted.

11-02-2009

Elysia

As a side note, shared_ptr is also available in TR1: std::tr1::shared_ptr and in C++0x: std::shared_ptr.

11-02-2009

SterlingM

Okay I got it working how I wanted it. Another question though, is there any way I could check whether a Room was a Bathroom or Bedroom? Mainly to have a Hallway toString() looks something like this

Room 1 is a //Bedroom or Bathroom
It consists of ...

Then continue along

11-02-2009

Daved

That should not be part of the Hallway code, that should be part of the Bedroom or Bathroom toString methods (or part of the Room toString method if you wanted to get a little fancier).

If you don't want that part of the toString() for Bedroom and Bathroom, you can have the Hallway do something like this:

Yeah I had planned on putting it into Room's toString(), but how can a Room pointer check what type of Room it is? Is there a function for situations like this?

11-02-2009

SterlingM

Ah okay, the above code got posted before I posted.

11-03-2009

YuJunheng

---"Polymorphism only works on pointers or references."
This is the answer.
For more, please refer to STL allocator.

11-03-2009

Elysia

You should not rely on deducing the type of the pointer or object. You should rely on the proper functions being called by the compiler.
Derive multiple classes from Room, each with your different type of room and overload your virtual function for each of them. When called, the proper function in the proper class will be called due to polymorphism. You do not need to know the type, unlike Java.

11-03-2009

Daved

>> you can use dynamic_cast
You can, but that's a bad idea here and a bad habit to get into. Don't do it.

>> how can a Room pointer check what type of Room it is?
It doesn't have to. If you use the Room's toString() method, you could do something like this:

Code:

cout << "Room " << room_id << " is a " << getRoomTypeName() << '\n';

Like in my previous example, getRoomTypeName would be a virtual function that is implemented in the derived classes to return the room type as a string.

If you find yourself trying to identify which derived type your Room pointer points to, you need to rethink what you're doing. Usually, whatever information you are trying to get (in this case, the type of room as a string) can be moved into a separate virtual function that can then be called on the Room pointer. That way you don't need to know what derived class it is, the virtual function will handle that for you.