Polymorphism; How to get the specific class?
Alrighty, so.
I have an (abstract) class named BaseObject, whose purpose is just to be extended upon. Next, I have a VisualObject class, which inherits from the BaseObject class. Next, I have a Player class, which inherits from the VisualObject class and the BaseObject class (through the VisualObject class).
The thing is, I am currently looping through a list of BaseObjects (which get added to the list when I create an instance of the Player or VisualObject class) and trying to find out if the object I have looped into is a Player class. That part is simple; I have been able to identify which BaseObject in the list corresponds to a Player object.
The part I'm having trouble with is that I have another class, TileMaster, who wants to change the coordinates of the instance of the player identified through the previous loop, but the BaseObject class doesn't have x or y variables, but the Player (and VisualObject) do.
The way that I have the engine set up, I am unable to just reference the Player object itself; It is being created by another object in a different part of the program.
Here is some code to help identify what I am trying to do:
Code:
BOOST_FOREACH (BaseObject* object, baseObjects) //loop through the list
{
// if the variable set in the BaseObject is a Player set number
if(object->objectType == 2)
// allow the tile master to change properties of the Player by ONLY knowing the BaseObject. Problems here
tilemaster->SetPlayerPos(object, THE_X_I_CHOOSE, THE_Y_I_CHOOSE);
}
Player.cpp:
Code:
Player::Player(int numPlayer) :
VisualObject("media/player.png"),
thisPlayerNum(numPlayer),
isMoving(false),
isJumping(false),
objectType(2) // identifies that the object type looped through is a player
{
//...
}
VisualObject.cpp:
Code:
VisualObject::VisualObject(const std::string& filename) :
BaseObject(),
surface(NULL),
x(0),
y(0),
objectType(1) // identifies it as a VisualObject
{
// ...
}
BaseObject.cpp:
Code:
BaseObject::BaseObject() :
objectType(0)
{
// ...
}
Any ideas?
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
dwdude
The thing is, I am currently looping through a list of BaseObjects (which get added to the list when I create an instance of the Player or VisualObject class) and trying to find out if the object I have looped into is a Player class. That part is simple; I have been able to identify which BaseObject in the list corresponds to a Player object.
That sounds like it defeats the purpose of polymorphism. The base class isn't supposed to know about who is derived from it.
Nowhere do you mention virtual functions. Virtual functions are the thing that makes the difference between true polymorphism, and just a fancy way of doing basic procedural, non-OO coding. Maybe you should rethink your design, especially if your design does not adhere to the IS-A principle of public inheritance (derived class IS-A base class).
Regards,
Paul McKenzie
Re: Polymorphism; How to get the specific class?
I was hoping the use of virtual functions was assumed :)
Perhaps it's not true, pure polymorphism. It's not so much of the BaseObject needing to know what class derives from it as it is for another class to know. Is there any way to do so?
Re: Polymorphism; How to get the specific class?
The notion of a BaseObject which *everything* inherits from doesn't fit the C++ paradigm very well. It's really more of a Java concept. You should consider whether or not it's really necessary here. What does having that BaseObject get for you?
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
Lindley
The notion of a BaseObject which *everything* inherits from doesn't fit the C++ paradigm very well. It's really more of a Java concept. You should consider whether or not it's really necessary here. What does having that BaseObject get for you?
Not everything inherits the BaseObject class; Just VisualObject class, my player class, and a (soon to be) enemy class.
The usage of the BaseObject in this instance helps with the drawing of those entities to the screen in an orderly, manageable fashion. Looping through a list of BaseObjects, calling their move functions, collision detecting functions, and draw functions in a few lines of simple code sounds like KISS to me.
Re: Polymorphism; How to get the specific class?
The problem you are describing fits the visitor pattern. Here is in a nutshell how it would work for your example:
Code:
#include <iostream>
class Tilemaster;
class BaseObject {
public:
virtual void accept(Tilemaster& t);
};
class Player : public BaseObject {
public:
virtual void accept(Tilemaster& t);
void setPos(int x, int y) { std::cout << "Move to " << x << "," << y << std::endl; }
};
class Tilemaster {
public:
void movePlayer(BaseObject& obj) { /* move if object is player */ obj.accept(*this); }
void visit(BaseObject& obj) { /* do nothing */ }
void visit(Player& obj) { obj.setPos(42,24);}
};
inline
void BaseObject::accept(Tilemaster& t) {t.visit(*this);}
inline
void Player::accept(Tilemaster& t) {t.visit(*this);}
int main() {
Tilemaster t;
BaseObject* obj1 = new BaseObject(); // or any other subclass
t.movePlayer(*obj1); //nothing happening
BaseObject* obj2 = new Player();
t.movePlayer(*obj2); // obj2.setPos being called
delete obj1;
delete obj2;
}
Re: Polymorphism; How to get the specific class?
Why the problem fit for visitor pattern ?
Thanks.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
Lindley
The notion of a BaseObject which *everything* inherits from doesn't fit the C++ paradigm very well. It's really more of a Java concept.
What's this "C++ paradigm" you're referring to? I've never heard about it. Is it something you've invented yourself?
Do you mean that C++ rules out certain OO designs? I've never heard of that either.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
Peter_APIIT
Why the problem fit for visitor pattern ?
The Visitor pattern is based on a so called double dispatch. It's an OO technique to ask objects what derived class they are. It's a typesafe downcast if you will.
And this is what the OP wants. He has a bunch of derived objects known only by their common base class. Now he wants each of them to reveal its actual derived class (so he can call methods present in the derived classes).
In my view the Visitor patterns generally is overused and thrown in as a sort of Swiss knife to fix all sorts of flawed designs where polymorphism and interface inheritance haven't been properly used.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
dwdude
The part I'm having trouble with is that I have another class, TileMaster, who wants to change the coordinates of the instance of the player identified through the previous loop, but the BaseObject class doesn't have x or y variables, but the Player (and VisualObject) do.
The question then is: Why doesn't BaseObject have x and y variables? Or alternatively, why do Player and VisualObject have x and y variables?
In a polymorphic design the base class must "cover" for all its intended derived classes. This means code written using base class variables should work regardless of which derived object is plugged in. With a fancy name this is called the Liskov substitution principle and you're breaking it so you don't have a valid polymorphic design.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
nuzzle
What's this "C++ paradigm" you're referring to? I've never heard about it. Is it something you've invented yourself?
Do you mean that C++ rules out certain OO designs? I've never heard of that either.
It's another way of saying "Don't try to write C++ as if it were Java. There are often better approaches." But you know that, you're just being pedantic.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
nuzzle
The question then is: Why doesn't BaseObject have x and y variables? Or alternatively, why do Player and VisualObject have x and y variables?
In a polymorphic design the base class must "cover" for all its intended derived classes.
:confused: When designing a class, one typically does not know yet, what specializations of the class will emerge later in the design process (one of the fundamental principles of OO as it allows extendibility). So a base class cannot "cover" (whatever that means) for all derived classes.
Quote:
Originally Posted by
nuzzle
This means code written using base class variables should work regardless of which derived object is plugged in. With a fancy name this is called the Liskov substitution principle and you're breaking it so you don't have a valid polymorphic design.
The Liskov substitution principle states that derived class objects must behave correctly when used as base class objects (the opposite of what you state above). Adding variables and methods to derived classes does not at all break this principle.
The problem in the OP's design is of different nature: The code iterates over a vector of BaseObject pointers, while it should iterate only over the VisualObjects. Keeping those in a separate vector from the beginning (or completely abandoning the concept of the BaseObject) would probably be the best solution.
Quote:
Originally Posted by
nuzzle
In my view the Visitor patterns generally is overused and thrown in as a sort of Swiss knife to fix all sorts of flawed designs where polymorphism and interface inheritance haven't been properly used.
Overuse of the pattern is usually a sign for a too deep class hierarchy, i.e. inheritance having been used where it should not be. Trying to solve this with polymorphism easily leads to bloated base classes with a lot of virtual methods that only make sense for some derived classes. If I have to chose between those two alternatives, I chose the visitor pattern.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
Lindley
It's another way of saying "Don't try to apply the principals you may have learned in Java directly to C++. There are often better alternatives." But you know that, you're just being pedantic.
Sure, just because both Java and C# use an implicit top class doesn't mean the first thing you should do in C++ is to mimic that and introduce an Object class all your other classes inherit. I fully agree with that.
What I have problems with is when it's suggested that it somehow goes against the very nature of C++ to use a common top class. Nothing could be more wrong. If you think your design would benefit from a top class then C++ doesn't stand in your way. In fact the virtual inheritance mechanism makes it quite straightforward to have one.
Re: Polymorphism; How to get the specific class?
I have nothing against base classes, or even deep hierarchies when appropriate.
But if you derive everything from a single class, then there must be some virtual method or property that every object in your design needs to possess. Otherwise, it's fairly pointless. That isn't impossible, but it seems like it would be fairly rare.
If you're just looking to be able to store arbitrary objects together and recover them later via a cast, then something like boost::any would probably be more appropriate.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
treuss
:confused: When designing a class, one typically does not know yet, what specializations of the class will emerge later in the design process (one of the fundamental principles of OO as it allows extendibility). So a base class cannot "cover" (whatever that means) for all derived classes.
In polymorphic design you start out with an abstraction in the form of a base class. The base class defines a type (essentially the public methods and their behavior). Any derived class must abide (in the Liskov sense) with the base class type. You can change anything anytime during a design process - except that.
Extensions to a polymorphic design is according to the Open/Closed principle. When you "plug in" a new derived class it will work "seamlessly" with existing code. This is what OO extendibility is about. Mere creating a derived class or adding a method to an existing one is not.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
Lindley
But if you derive everything from a single class, then there must be some virtual method or property that every object in your design needs to possess. Otherwise, it's fairly pointless. That isn't impossible, but it seems like it would be fairly rare.
You're imposing your lack of imagination on others, even trying to make a "C++ paradigm" out of it.
Re: Polymorphism; How to get the specific class?
Well, I'm not the only one. The "God Object" is called an anti-pattern for a reason.
But if you think it's so great, I'd be curious to see a justifiable example.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by nuzzle
You're imposing your lack of imagination on others, even trying to make a "C++ paradigm" out of it.
I think that it is indeed a paradigm, and is implied by the core language and standard library, and even stated somewhat explicitly by Stroustrup. In Gotcha #97, Stephen Dewhurst claimed that:
Quote:
Originally Posted by Stephen Dewhurst
More than a decade ago, the C++ community decided that the use of "cosmic" hierarchies (architectures in which every object type is derived from a root class, usually called Object) was not an effective design approach in C++.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
Lindley
Well, I'm not the only one. The "God Object" is called an anti-pattern for a reason.
The "god class" anti-pattern warns you not to build a design around one big all-knowing class. In such a design one class controls everything and uses other classes as mere records to shuffle data in and out from. I don't think it's even possible to misuse a common top class according to this antipattern but if you manage to find a way you definately shouldn't do it.
So a common top class will sit at the top of all inheritance hierarchies, and if you want to call it a "god class" because of that you may do so. This however won't make it bad in the "god class" anti-pattern sense.
Quote:
But if you think it's so great, I'd be curious to see a justifiable example.
In C++ there's no language-wide top class so here you would introduce one to give all application classes a common functionality. Still Java and C# are good examples of what kind of functionality that could be. The only requirement really is that it should be of clear application-wide interest.
Here are a few specific examples.
Say for example you would like to enumerate all objects. This would make every application object identifiable. Then you would like to introduce a counter in all objects to hold a unique number.
Or maybe you would want to standardise on an application wide memory management scheme. Say you want to use a reference counting smart pointer. If you want to make it intrusive you would like all objects to hold a reference counter.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by
laserlight
I think that it is indeed a paradigm,
I think it's great that C++ doesn't enforce a common top class. This is only to be expected from a language which supports multiple programming paradigms. But just because C++ doesn't force it on you doesn't mean it's wrong to introduce a top class in your own applications.
The Stephen Dewhurst reference you posted agrees with my view. It states that a "cosmic" top class in C++ would be bad. I don't think any C++ programmer wants a "cosmic" top class, I certainly don't. But again, this doesn't mean it's wrong to use a common top class of your own design to good effect in your own application, and it certainly isn't anti-C++ in any way.
In short, the fact that the C++ language doesn't enforce a "cosmic" top class on you doesn't make it a paradigm that you shouldn't introduce an application-wide one yourself.
Re: Polymorphism; How to get the specific class?
Quote:
Originally Posted by nuzzle
But again, this doesn't mean it's wrong to use a common top class of your own design to good effect in your own application, and it certainly isn't anti-C++ in any way.
I think that you are just unnecessarily harping on semantics. Let us review the context:
Quote:
Originally Posted by dwdude
I have an (abstract) class named BaseObject, whose purpose is just to be extended upon.
Quote:
Originally Posted by Lindley
The notion of a BaseObject which *everything* inherits from doesn't fit the C++ paradigm very well. It's really more of a Java concept. You should consider whether or not it's really necessary here. What does having that BaseObject get for you?
A class "whose purpose is just to be extended upon" certainly does not sound like the use of "a common top class of your own design to good effect in your own application", and "a BaseObject which *everything* inherits from" really means a "cosmic" base class that is so general that it is blindly all inclusive. This differs from an application wide base class that provides just the right amount of generalisation for an application specific problem.
This, I think, is the lesson to learn: you should avoid generalising classes beyond what is appropriate.