Jump to content
  • Advertisement
Sign in to follow this  
cdenvir

c++ query

This topic is 4841 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

Hi This may possibly be a very simple question to most of you but i've searched the net and haven't found a solution yet Basicly what i'm trying to do is create a superclass and have a subclass branching off that using public inheritance. The problem is that if i create an instance of the superclass i can't access the subclasses methods i'll give an example: class game { public: game(); void setGameType(); string getGameType(); private: string _gameType; }; class doom : public game { public: doom(); int getFieldofView() private: int fieldofView; }; void main() { game a; a = doom(); a.fieldofView() -- this won't work i can only access getGameType() and setGameType(). I've tried using a dynamic cast to get it to work but that appears to only work backwards - ie convert a doom object into a game object and not the other way around. I'm used to using java which doesn't have these type of problems. any help appreciated

Share this post


Link to post
Share on other sites
Advertisement
This would definitely not work in Java either. If you inherit doom from game, doom will inherit the methods from game, that's all that happens. That's why you can't call "getVieldOfView" on a game object.

And yes, you will have to cast your game object to a doom object to call that method, but that's intended. How should the compiler know what method you are trying to call if you do a game->getFieldOfView?

Share this post


Link to post
Share on other sites
First, Java does have this "problem" too. However, it's not a problem because it's doing exactly what it's supposed to do.

Second, what you want in this case is something like:

game* pGame;
pGame = new Doom();
dynamic_cast<Doom*>(pGame)->getFieldOfView();
// don't forget to delete pGame when you are done with it


Non-primitive data types are always references in Java. Depending on how you look at it, you need either pointers or references in C++.

However, relying on a cast to a subclass to call something is often avoidable and you should not do it if there is a reasonable alternative.

Share this post


Link to post
Share on other sites
Quote:
Original post by BitMaster
However, relying on a cast to a subclass to call something is often avoidable and you should not do it if there is a reasonable alternative.


Quoted for emphasis.

Share this post


Link to post
Share on other sites
That shouldn't work in Java because game doesn't have a method called fieldOfView. You could make a virtual function in game called fieldOfFiew and you would be able to access a subclasses method.

Share this post


Link to post
Share on other sites
Why would you want to call getFieldOfView?

You're missing a big design point:

The Game class should provide an adequate interface to use the game. Users of the game class won't need to call getFieldOfView because it is not necessary for using the Game. If one of Doom's functions needs to call getFieldOfView then it can do it if it needs to.

If you don't understand that a user of Game doesn't need to be able to call getFieldOfView send me a PM.

Pete

Share this post


Link to post
Share on other sites
A little more on petewood's point.

General purpose client's would have access to the game object, and would never know about or need to call Doom specific functions like getPointOfView. I mean if you have a general purpose score recording mechanism, or a general purpose mechanism for having players chat ... these would not be related in any way to Doom3 specific function calls. And anything which is Doom3 specific would retain pointers to the Doom3 game instance, not the general game instance.

It is quite possible that this object obtained the Doom3 game instance initially by doing a dynamic_cast<Doom3Game*>(gameInstance), but it would not store a Game* internally if it knows it wants a Doom3Game, it would store the Doom3Game.

For instance, my little turn based sci-fi library has classes like this:

GameObject - persitable and findable from the GameObjectManager.
PhysicalObject : GameObject - has location.
SolarSystem : PhysicalObject - has solar system related stuff.
Fleet : PhysicalObject - has star ship fleet information.

Fleet's know what SolarSystem they are in - not what GameObject they are in. SolarSystem's know what PhysicalObjects are within them, not what GameObjects.

All of these items are initially loaded when a file is read and added to a GameObjectManager, and then on the second pass, they look up their associated objects - so during the initial load operation, every single one of these object conections was made using code like this:

GameObject *object = gameObjectManager->LookupObjectById(objectId);
SolarSystem *solarSystem = dynamic_cast<SolarSystem*>(object);
if(solarSystem == 0)
{
// these line are actually wrapped in a GENERATE_EVENT macro, for debug purposes, but you get the idea.
Event event(EventType.Error, ...)
systemLogger->Log(event);
throw event;
}
currentFleet->CurrentLocation(solarSystem);

note that the only functions which do the dynamic_casting are load functions. While the game is running, every object retains strongly typed pointers to the items it expects.

Share this post


Link to post
Share on other sites
Thanks for all the replys

I picked up a good amount of info but i still have a couple more querys on the subject. I've been trying to avoid dynamic casting and from a couple of posts it sounds like thats probably a good idea. However i think in this situation - unless i'm missing something, its unavoidable. I'll just give another quick example


. SuperClass
. / | \
ClassA ClassB ClassC

If i make an array or vector of SuperClass objects and depending on user input ClassA B or C would be stored in that vector.

Example:


void main()
{
int choice;
vector<SuperClass> vect;

cout << enter 1 2 or 3 to push on classA,B or C;
cin >> choice;

switch (choice)
{
case 1 : vect.push_back(classA()); break;
case 2 : vect.push_back(classB()); break;
case 3 : vect.push_back(classC()); break;
default : break;
}
}

This program wouldn't exactly do anything but my point kind of is that if you need to create a heap of generic objects (SuperClass) to group together all of its subclasses in the 1 variable this seems like the only way to do it.. and from here the only way to extract the objects from what previous people were saying is by using dynamic casting.

If superclass objects are not ment to be declared and assigned subclass objects then i'm confused to why anyone would even use a tree structure type system - other than the obvious code reuse and possibly that its easier to read. I might as well just create ClassA, ClassB and ClassC seperately and ignore the use of SuperClass or any other type of tree structure.

Thanks again for the help

Share this post


Link to post
Share on other sites
The idea is to use virtual functions to get the information you require.

For example

class Super { public: virtual int GetValue()=0; };
class A : public Super { public: virtual int GetValue() { return 1; } };
class B : public Super { public: virtual int GetValue() { return 2; } };
class C : public Super { public: virtual int GetValue() { return 3; } };


The reason Java dosn't have this "problem" is because all functions are virtual in Java - here this isn't automatic - you must specify functions as virtual in C++ if you want to do this.

There are only limited situations where you need the actual type back again. Then you can either use C++'s RTTI functionality, or make your own.



Also, another important note is that you can't do what you just said:

BAD you can't put non-SuperClass objects in a vector of SuperClass objects
vector<SuperClass> vect;
switch (choice)
{
case 1 : vect.push_back(classA()); break;
case 2 : vect.push_back(classB()); break;
case 3 : vect.push_back(classC()); break;
default : break;
}


OK using a raw pointer: remember to delete things in vect before you get rid of vect itself
vector<SuperClass*> vect;
switch (choice)
{
case 1 : vect.push_back(new classA()); break;
case 2 : vect.push_back(new classB()); break;
case 3 : vect.push_back(new classC()); break;
default : break;
}


GOOD using a shared pointer - things in vect are deleted for you when you finish with vect
vector<boost::shared_ptr<SuperClass> > vect;
switch (choice)
{
case 1 : vect.push_back(new classA()); break;
case 2 : vect.push_back(new classB()); break;
case 3 : vect.push_back(new classC()); break;
default : break;
}


You must use a pointer, because vector will only allow a single type in it. So when you have a vector of SuperClass objects, you can only put SuperClass objects in it (not children). If you have a pointer to SuperClass - "SuperClass*" (or the shared pointer) is your one type, but that one type can then point to many different types (SuperClass and any direct or indirect children).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!