Abstact Class problem (?)

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Abstact Class problem (?)


      Here is a question that is best suited by example:

      Source Code

      1. class IActor
      2. {
      3. u_long m_ID;
      4. u_int x;
      5. public:
      6. virtual SetID( u_long ID ) = 0;
      7. virtual u_long GetID( void ) =0;
      8. virtual void SetPositionX( uint PosX ) = 0;
      9. virtual uint GetPositionX( void ) = 0;
      10. // and some more methods.
      11. };
      12. class CGhost : public IActor
      13. {
      14. SetID( u_long ID );
      15. GetID( void );
      16. void SetPositionX( uint PosX );
      17. uint GetPositionX( void );
      18. }
      19. class CPlayer : public IActor
      20. {
      21. SetID( u_long ID );
      22. GetID( void );
      23. SetName(std::string PlayerName ); // NEW
      24. void SetPositionX( uint PosX );
      25. uint GetPositionX( void );
      26. }
      Display All

      As you can see "CGhost" inherits all the 'properties'
      from IActor as well as CPlayer with the addtion of
      a method called "SetName(..)".

      Now then, when I want to add an print out my list of

      Source Code

      1. PrintActorList( void )
      2. { shared_ptr<IActor> p;
      3. for ( ActorMap::iterator x = m_ActorMap.begin(); x != m_ActorMap.end(); x++ )
      4. {
      5. p = GetActor( x->first );
      6. ulong id = p->GetID();
      7. switch ( id )
      8. { // Pacman.
      9. case 0 : { std::string s = p->GetName();
      10. wsprintf(ErrorBuff, "Player Type %d, Player Name: %s.\n", p->GetID(), s.c_str() );
      11. break;
      12. }
      13. // Ghost.
      14. case 1 : { wsprintf(ErrorBuff, "Player Type %d, Ghost.\n", p->GetID() );
      15. break;
      16. }
      17. }
      18. MessageBox(NULL, ErrorBuff ,"Error",MB_OK);
      19. }
      Display All

      But, now I want to check and see if it is adding my actors
      to my list. The problem is '"GetName(..)" is not part of IActor'. Is there a way of getting around this problem
      with out having to write a pure method for "SetName(..)" in IActor? Logically it does not make sence
      to do it since IActor is a "generic" player, (which is my only option right now.)

      Here is how I add either a ghost or player to a std map.

      Source Code

      1. unsigned int CGame::AddActor( boost::shared_ptr<IActor> const Actor )
      2. {
      3. m_ActorMap[m_LastActorId] = Actor;
      4. Actor->SetID( m_LastActorId );
      5. ++m_LastActorId;
      6. return ( m_LastActorId );
      7. }

      Thanks again guys :)

    • What would be wrong with adding a name parameter to actor? It would in essence be similar to the id... in that it is another way to refer or describe that object.

      However if you are saying that you definitely don't want name to be part of your interface class (CActor) then why don't you add a GetName(...) function to your CPlayer class that retrieves the name (I assume a std::string in your case) for that CPlayer object?

      Also, if you want to know if you are adding objects to your list you could do a MyList.size() (depending on what kind of list/vector/etc... you are using)

      Am I understanding your question correctly?


      The post was edited 1 time, last by Alien_Attack ().

    • This kind of thing happens all the time in game programming.

      You get around the problem by casting the IActor to your CPlayer class, and then you'll have access to the methods in CPlayer.

      But, you ask, how do I know which class is really being pointed to by the IActor? You can do this a number of ways.
      1. Use dynamic_cast and check the return - if it is non-null the cast succeeded. Downside: runtime type checking adds data and is not advised in all situations.
      2. Add a GetType()=0; API to IActor. Create a CActor class that implements GetType(), and use that to store and retieve what kind of IActor object you are pointing to. The GetType() could return an enum, but that creates other problems I mention in the Events chapter. Better to return a GUID or a hashed string that is managed by some other class.
      Author, Programmer, Brewer, Patriot
    • RE: Abstact Class problem (?)


      IActor is a 'person' but only has position, state (dead or alive), Points, etc. Both Ghost and Player have these 'properties', but Ghost does not have a name where as Player does. To me this makes since not to put "GetName()'
      or 'SetName()' in the IActor, but to implment these methods in CPlayer only. This way Ghost will not have a name cuz it doesnt need one. This is strickly a design issue, and to me makes sence. (??)

      Here is a sniplet of an error I get now:

      Source Code

      1. boost::shared_ptr<CPlayer> Player(new CPlayer("Bob") ); // ERROR: C2259: 'CPlayer' : cannot instantiate abstract class AddActor( Player );

      I am not sure why I am getting this problem. I think this goes back to the abstract class, but I cant seem to see or understand the problem. Help.

      I do have a "GetType() const=0; in IActor :) I have enum ACTORTYPE {PLAYER=0, GHOST } But after reading last week in your book, this is not a good idea to do it this way. (?) Could I just do something like this?

      const char *CPlayer::m_Type = "Player";
      const char *CGhost::m_Type = "Ghost";

      However, I am still not sure how to manage the type(s)
      Could you expand your explination of doing it this way please?

      Also, I was thinking of 'restructuring' how I do inheritance: IActor -> CActor -> Ghost, CActor-> CPlayer However, I am not convinced that this will take care of my problem as posted above. However, would this be a better" of designing inheritance?

      Thanks again,

    • RE: Abstact Class problem (?)

      The 'cant instantiate abstract class' error is when you've got a class that inherits from an interface class, like IActor, and doesn't implement one of the pure virtual functions. Here's an example:

      class IAbstract
      virtual int MakeThisOrElse()=0;

      class CNotAbstract : public IAbstract
      int Something1();
      int Something2();
      // note - I didn't define a MakeThisOrElse()!

      void main()
      CNotAbstract notAbstract; // you get the error here.


      Get it?

      Certainly one way to create your types is by looking at how the Event system worked in the book. It defines event types as a hashed string, makeing sure that the string is unique when any particular event is registered with the system.

      Take a look at it and see if you can repurpose the event type system for your actor type problem.
      Author, Programmer, Brewer, Patriot
    • RE: Abstact Class problem (?)


      After digging around in some of my UML, OOP, and programming books I figured out the problem. My understanding is if an abstract class has it methods with (for example) "foo() const = 0;" then you can not add any of your own methods to any derived class. If
      you have your methods in the abstract class like this; "foo() = 0" then you may have other methods that are not defined in the abstract class in the derived class.

      Of course, I could be wrong at this, but this how I interpret the problem. (?)

      Thanks MrMike for taking time to help! And you too Alien_Attack :)

    • RE: Abstact Class problem (?)

      well... not quite. There's no restriction on adding methods to derived classes. You just have to be careful that your base class functions are virtual. If they'e not, you may not get the behaviour you expect. Pure virtual just means you MUST override them (as in Mr Mikes example.)

      IMHO it's much better style to avoid "type" members if you can; that's the job of polymorphism. If you find yourself constantly downcasting to get to a method in a derived class from a function that is supposed to deal with a base class, like your Print example, that's a sure sign for some refactoring. You could either move the GetName function up the hierarchy, so all IActors have it and Print can care less what class it is dealing with, or you can leave the responsibility of knowing how to print to the classes themselves:

      Source Code

      1. class IActor
      2. {
      3. // blah
      4. public:
      5. virtual void Print(const std::ostream& out) = 0;
      6. }
      7. class Ghost :public IActor
      8. {
      9. void Print (const std::ostream& out)
      10. { // print ID and Type. }
      11. };
      12. class Player:public IActor
      13. {
      14. void Print (const std::ostream& out)
      15. { Print Name, ID and Type. }
      16. };
      Display All

      or even better, implement operator << instead of Print.

      If you haven't read Scott Meyers' Effective C++ books, I'd highly recommend them. They're short and too the point, not like my posts :P
      hope that helps.
    • RE: Abstact Class problem (?)

      Eh, I don't see whats wrong with good old printf(). Scanf() can be funky (I've gotten crazy errors while using it in a loop), but printf() is a dream to work with. Hell, the language was built around it.

      As for the problem at hand. I had written up a reply, but then I realized I'm entirely clear why there is a "const" before the "=0," and I was too lazy to grab my C++ book, and the Google search didn't answer my question, then I got frustrated, closed Firefox, and lost my post I was typing. I'm sure you all wanted to know that.
      -Larrik Jaerico


      The post was edited 1 time, last by Larrik ().

    • RE: Abstact Class problem (?)

      I didn't say there was anything wrong with printf(). I just happen to like the std library. My point was more about the design decision of where to put the Print function.

      But since you brought it up :P, the advantage of implementing op << and >> is that they can be used with any stream, not just cout/cin. For example, if the Ghost class had these, you could not only print your data to stdout, but without changing the class you can serialize to/from XML, etc etc. Depends on your requirements.
      If all you ever want to do is send some strings to stdout, printf is definitely the way to go.
    • RE: Abstact Class problem (?)

      well, there's no single right way. Programming would be pretty boring if there were, eh? I mean, where would we be if we couldn't get off on these totally obscure tangents every time some poor innocent soul posts a completely legitimate question. :P

      btw, sorry for hijacking your thread, Sabrina.