Results 1 to 29 of 29

Thread: An Abstract Class Question

  1. #1

    Thread Starter
    PowerPoster Halsafar's Avatar
    Join Date
    Jun 2004
    Location
    Saskatoon, SK
    Posts
    2,339

    An Abstract Class Question

    Alright I am trying to make a universal stat loading routine.
    So I can load the stats of any unit into any unit class with 1 function.

    I already wrote the functin awhile ago, but it is used for loading into a passed struct variable...I need to load the stats into a class...So I need to be able to pass a class, but the class could be human, vehicle, etc...
    So far
    I am not sure how to write the function header
    LoadStats(MoveableObject Object)
    {
    }

    This is what I have...

    Now the variables like
    m_HP
    m_ARMOR
    m_RunSpeed

    they are all private in the human class

    how do I have the abstract class MoveableObject acsess those...how do I set it up so by passing the human class into that function that I modify the human class private.
    "From what was there, and was meant to be, but not of that was faded away." - - Steve Damm

    "The polar opposite of nothingness is existance. When existance calls apon nothingness it shall return to nothingness." - - Steve Damm

    "When you do things right, people won't be sure if you did anything at all." - - God from Futurama

  2. #2

    Thread Starter
    PowerPoster Halsafar's Avatar
    Join Date
    Jun 2004
    Location
    Saskatoon, SK
    Posts
    2,339
    if this is not possible, would it be wise to then create a stat loading function for each unit...

    I am using a system similar to RA2 (rules.ini)
    "From what was there, and was meant to be, but not of that was faded away." - - Steve Damm

    "The polar opposite of nothingness is existance. When existance calls apon nothingness it shall return to nothingness." - - Steve Damm

    "When you do things right, people won't be sure if you did anything at all." - - God from Futurama

  3. #3

    Thread Starter
    PowerPoster Halsafar's Avatar
    Join Date
    Jun 2004
    Location
    Saskatoon, SK
    Posts
    2,339
    Call:
    Load_Stats(App_Path + "/data/stats/rules.txt",&Player);

    Function:
    void GameEngine::Load_Stats(string szFileName, MoveableObject *Object)

    Error on Call:
    'type cast' : conversion from 'class Human *' to 'class MoveableObject *' exists, but is inaccessible
    "From what was there, and was meant to be, but not of that was faded away." - - Steve Damm

    "The polar opposite of nothingness is existance. When existance calls apon nothingness it shall return to nothingness." - - Steve Damm

    "When you do things right, people won't be sure if you did anything at all." - - God from Futurama

  4. #4

    Thread Starter
    PowerPoster Halsafar's Avatar
    Join Date
    Jun 2004
    Location
    Saskatoon, SK
    Posts
    2,339
    The same thing happens when I
    Human Player;
    MoveableObject *Test = &Player;

    I get the same error, cannot typecast..available...inaccesible.
    "From what was there, and was meant to be, but not of that was faded away." - - Steve Damm

    "The polar opposite of nothingness is existance. When existance calls apon nothingness it shall return to nothingness." - - Steve Damm

    "When you do things right, people won't be sure if you did anything at all." - - God from Futurama

  5. #5
    Retired G&G Mod NoteMe's Avatar
    Join Date
    Oct 2002
    Location
    @ Opera Software
    Posts
    10,191
    Originally posted by Halsafar
    The same thing happens when I
    Human Player;
    MoveableObject *Test = &Player;

    I get the same error, cannot typecast..available...inaccesible.

    Not sure....but don't you have to make an object first...before you do that....in VC I think you only get a warning for it. But it might be your error....

  6. #6
    Retired G&G Mod NoteMe's Avatar
    Join Date
    Oct 2002
    Location
    @ Opera Software
    Posts
    10,191

    Re: An Abstract Class Question

    Originally posted by Halsafar

    how do I have the abstract class MoveableObject acsess those...how do I set it up so by passing the human class into that function that I modify the human class private.

    Add them to the base class. Then all the other classes that inherits from that class will have them. And if you need to access functions in the Human class and so on, make the function in the base class as viritual....something like this:

    Code:
    //The base class
    class MoveableObject{
    
    public:
    
    	virtual void LoadStats() = 0;
    
    private:
    	int m_HP;
            m_ARMOR;
            m_RunSpeed;
    };

  7. #7

    Thread Starter
    PowerPoster Halsafar's Avatar
    Join Date
    Jun 2004
    Location
    Saskatoon, SK
    Posts
    2,339
    I got as far as your second post.

    As for that typecast error...I created the object first.
    I cannot convert from *MoveableObject to *Human
    Which makes sense, except this is how abstract classing works, so I aint sure whats wrong.

    It even says the cast is avialable to unassecable

    See my plan is to make a function private in the game engine which is built to load up the stats for any unit...Already written I made it work just fine.

    Then I wish to pass a pointer to that function to any unit class apon creation to allow it to load itself up at any time.

    Problem is, I cannot seem write the OOP into the function, the whole "this will work with any unit class" part.
    Last edited by Halsafar; Sep 18th, 2004 at 11:22 PM.
    "From what was there, and was meant to be, but not of that was faded away." - - Steve Damm

    "The polar opposite of nothingness is existance. When existance calls apon nothingness it shall return to nothingness." - - Steve Damm

    "When you do things right, people won't be sure if you did anything at all." - - God from Futurama

  8. #8

    Thread Starter
    PowerPoster Halsafar's Avatar
    Join Date
    Jun 2004
    Location
    Saskatoon, SK
    Posts
    2,339
    This works, just fine.

    PHP Code:
    //part of game engine
    HPlayerHuman

    Human Player
    (&(Device3D), Timer.GetDeltaPointer(), VectorCircle);
    HPlayer = &Player;
        
    MoveableObjectunits;
    units HPlayer;

    Load_Stats(HPlayer);
    //-----------------------

    void GameEngine::Load_Stats(string szFileNameMoveableObject *Object)
    {
    //runs a functions which changes the private variable m_Walk
    //within the base class, which contains the Player Human class
    //which has a variable m_Walk private as well
    Object->SetWalkSpeed(10);  
    Object->SetRunSpeed(10);

    Problem is, the stats in the Human class are NOT changing.
    Does my Human class need to contain the functions SetRunSpeed and SetWalkSpeed?
    If not, I think I know why this aint working then?
    PHP Code:
    class Human : public MoveableObject //1
    class Human MoveableObject //2
    class Human : public, MoveableObject, Private MoveableObject //3
    class Human : private MoveableObject //4
    {
    private:
      
    UINT m_Walk;
    public:
      
    Update();   //Updates the unit given its actions called

    //1 = cannot acsess the private members of Human which are the variables
    //2 = type cast error "Cannot convert from MoveableObject* to HUman*
    //3 = error C2500: 'Human' : 'MoveableObject' is already a direct base class
    //4 = type cast error same as above //2

    So obviously to get a compile I have to use //1
    I am not sure what I am doing wrong.

    PHP Code:
    class MoveableObject
    {
    private:
      
    UINT m_Walk//Used to set contained unit class m_Walk private
    public:
      
    Update();   //Calls contained units Update function

    Any help would be appreciated.
    Last edited by Halsafar; Sep 18th, 2004 at 11:47 PM.
    "From what was there, and was meant to be, but not of that was faded away." - - Steve Damm

    "The polar opposite of nothingness is existance. When existance calls apon nothingness it shall return to nothingness." - - Steve Damm

    "When you do things right, people won't be sure if you did anything at all." - - God from Futurama

  9. #9
    Fanatic Member riis's Avatar
    Join Date
    Nov 2001
    Posts
    551
    When you make inherited classes, you should make variables, which are needed by child classes, protected.
    PHP Code:
    class MoveableObject
    {
    [
    b]protected:[/b]
      
    UINT m_Walk//Used to set contained unit class m_Walk private
    public:
      
    Update();   //Calls contained units Update function

    I'm also wondering what the first line of code ("HPlayer* Human") in your snippet is doing. I think it's obsolete, and can cause lots of errors. "HPlayer" is used as a variable later on, while "Human" is a class name.

    BTW, the way NoteMe told (implementing an extra method as a pure virtual function) is the way how to create an abstract class. That way you can ensure that you (or someone else) isn't able to create a "MovableObject" directly, but always need to create a "Human" or "Vehicle". You MUST implement the method in all instantiable derived classes, else they'll be abstract as well!

    BTW2, the derival method 1 should be allright. You should've run into problems as soon as you created the "Human" class. In case it worked at first, then you have done something which broke it. Try to remember what that was, and fix it.

  10. #10

    Thread Starter
    PowerPoster Halsafar's Avatar
    Join Date
    Jun 2004
    Location
    Saskatoon, SK
    Posts
    2,339
    Human* HPlayer //declared in public section of game engine
    Human Player(...) //done within main_loop or unit creation function
    HPlayer = &Player //set the pointer

    HPlayer is then used all over the game engine class to modify the Player instance.



    Yes my base (abstract) class MoveableObject has a virtual function
    just one

    virtual inline void Update();

    it is not defined
    See, I just need the Load_Stat function to be able to change a human class, or a car class...the variables will always be the same.
    So does that mean I need to contain those variables within the base class and the unit class? just one or the other?

    I'm seriouslly lost.
    Last edited by Halsafar; Sep 19th, 2004 at 02:04 AM.
    "From what was there, and was meant to be, but not of that was faded away." - - Steve Damm

    "The polar opposite of nothingness is existance. When existance calls apon nothingness it shall return to nothingness." - - Steve Damm

    "When you do things right, people won't be sure if you did anything at all." - - God from Futurama

  11. #11

    Thread Starter
    PowerPoster Halsafar's Avatar
    Join Date
    Jun 2004
    Location
    Saskatoon, SK
    Posts
    2,339
    This compiles, of course I skimmed out the stuff that don't matter...But it comes, and works, but it does not change the Human class (Player instance), it does not set the m_WalkSpeed to 10.

    PHP Code:
    class MoveableObject
    {
    protected:
      
    UINT m_WalkSpeed;
      
    UINT m_RunSpeed;
    public:
       
    virtual inline void Update()
      {
      }
        
    inline void SetWalkSpeed(int iValue)
    {
        
    m_WalkSpeed iValue;
    }

    inline void SetRunSpeed(int iValue)
    {
        
    m_RunSpeed iValue;
    }

    }; 
    PHP Code:
    //This then the human in its own header
    #include "clsMoveableObject.hpp"

    class Human : public MoveableObject
    {
    private:
       
    UINT m_WalkSpeed;
       
    UINT m_RunSpeed;
    pubilc
       inline void Update
    ();
    }; 
    PHP Code:
    //This is the start of the main game loop where the player
    //is created
    int GameEngine::game_MainLoop()
    {
    GenerateVectorCircle();

    Human Player(&(Device3D), Timer.GetDeltaPointer(), VectorCircle);
    HPlayer = &Player;
        
    MoveableObjectunits;
    units HPlayer;
    Load_Stats(App_Path "/data/stats/rules.txt",units);

    PHP Code:
    //This is the Load_Stat Function at is most basic
    void GameEngine::Load_Stats(string szFileNameMoveableObject *Object)
    {
    Object->SetWalkSpeed(10);
    Object->SetRunSpeed(10);

    Last edited by Halsafar; Sep 19th, 2004 at 02:14 AM.
    "From what was there, and was meant to be, but not of that was faded away." - - Steve Damm

    "The polar opposite of nothingness is existance. When existance calls apon nothingness it shall return to nothingness." - - Steve Damm

    "When you do things right, people won't be sure if you did anything at all." - - God from Futurama

  12. #12
    Fanatic Member riis's Avatar
    Join Date
    Nov 2001
    Posts
    551
    Originally posted by Halsafar
    Human* HPlayer //declared in public section of game engine
    Human Player(...) //done within main_loop or unit creation function
    HPlayer = &Player //set the pointer

    HPlayer is then used all over the game engine class to modify the Player instance.



    Yes my base (abstract) class MoveableObject has a virtual function
    just one

    virtual inline void Update();

    it is not defined
    See, I just need the Load_Stat function to be able to change a human class, or a car class...the variables will always be the same.
    So does that mean I need to contain those variables within the base class and the unit class? just one or the other?

    I'm seriouslly lost.
    If you make a function virtual in a class, it doesn't make the class abstract. If you want an abstract class (one of which no objects can be generated), you need a pure virtual function. This is accomplished in C++, by placing "= 0" behind the method. In that case you don't have to define the method (but you should do now, or at least when one of the derived objects calls that method). (The one exception is if you want the destructor to be a pure virtual method. The destructor of a base class is always called when a derived class is destroyed, and therefor should be implemented.)

    If the variables will always have the same name for all derived classes (like Human or Vehicle), then you can let them in the base class. Make sure they're at the "protected" access specifier (instead of "public" or "private"), so derived objects can access them! You don't have to redefine them in the derived class. I think it will work, but if you particularly want to access the variables in the base class, you need to place the proper scope in front of the variable name. (MoveableObject::m_WalkSpeed will hold the modified value, instead of m_WalkSpeed, which has the Human class as scope)

    I didn't mention this in my previous post, since I try to avoid such circumstances, and I'm not really familiar with them. It only complicates matters, since you have to explicitely specify the scope.

  13. #13
    Fanatic Member riis's Avatar
    Join Date
    Nov 2001
    Posts
    551
    Now your other post: remove the m_WalkSpeed and m_RunSpeed from the private access specifier in the Human class, and it should work fine
    I should've already seen it in the previous code you posted, but I guess it was still early over here

  14. #14
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594
    Here's the error:
    class Human : MoveableObject //2
    Default derivation of classes is private, so Human can't be cast to MoveableObject. You need to make derivation public here.
    All the buzzt
    CornedBee

    "Writing specifications is like writing a novel. Writing code is like writing poetry."
    - Anonymous, published by Raymond Chen

    Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.

  15. #15
    Retired G&G Mod NoteMe's Avatar
    Join Date
    Oct 2002
    Location
    @ Opera Software
    Posts
    10,191
    Originally posted by Halsafar
    Code:
    //This then the human in its own header
    #include "clsMoveableObject.hpp"
    
    class Human : public MoveableObject
    {
    private:
       UINT m_WalkSpeed;
       UINT m_RunSpeed;
    pubilc
       inline void Update();
    };
    [/code]

    I am pretty sure you can't make this inline.... because it has to be looked up in a vtable during runtime. Am I right you all mighty C++ gurus?
    Last edited by NoteMe; Sep 19th, 2004 at 07:17 AM.

  16. #16

    Thread Starter
    PowerPoster Halsafar's Avatar
    Join Date
    Jun 2004
    Location
    Saskatoon, SK
    Posts
    2,339
    This page shows much love all the time. Thanks for all yer tips.
    I do believe I can make this work.

    A little off topic, but I bet if a few of the common everyday posters on this site (like me ) combined their skills, we could make some kills apps and games...Apps to go along with the games.

    Anyway, I might have more questions later I do not have time as of now to play with the code... Gotta go out.

    Peace
    "From what was there, and was meant to be, but not of that was faded away." - - Steve Damm

    "The polar opposite of nothingness is existance. When existance calls apon nothingness it shall return to nothingness." - - Steve Damm

    "When you do things right, people won't be sure if you did anything at all." - - God from Futurama

  17. #17
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594
    Combined their skills, yes. Combined their time, no...
    All the buzzt
    CornedBee

    "Writing specifications is like writing a novel. Writing code is like writing poetry."
    - Anonymous, published by Raymond Chen

    Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.

  18. #18
    Retired G&G Mod NoteMe's Avatar
    Join Date
    Oct 2002
    Location
    @ Opera Software
    Posts
    10,191
    Originally posted by CornedBee
    Combined their skills, yes. Combined their time, no...

    So true...but you who are a genious........what do you think of my last asumption...does it make sense?

  19. #19
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594
    Hmm...

    MoveableObject::Update is marked virtual, right?

    Ok, so let's see. Basically, you can mark inline whatever you want. It's just a suggestion to the compiler after all. If the compiler is unable to inline it (and that's the case with a virtual function call) it won't.
    So inlining this function is pretty much useless.

    However, there's one exception here. You can tell the compiler explicitely to use a specific version of a function and ignore the vtable. The syntax for this looks pretty weird:
    ptr->SpecificClass::virtualFunction();
    This requires, of course, that the compile-time type of ptr is SpecificClass* or some derived class pointer, it cannot be a base class pointer.
    In this case, if SpecificClass:virtualFunction is marked inline, the compiler might inline the call. However, I'm not sure if any compiler does. This special call syntax is extremely rare and I've seen it used only once: deeply buried in the MFC code, which generally is not a good example of proper coding. It's an ugly hack there: unlike a call through the vtable, a direct call can be performed on a NULL pointer (but if you try to access any members in the called function, you'll still crash, because the this pointer will be NULL). The code looks something like this:
    Code:
    if(pWnd != NULL) {
      pWnd->DoSomething();
    } else {
      pWnd->CWnd::DoSomething();
    }
    and CWnd::DoSomething is written so that it works with a NULL this pointer.

    In general, though, making a virtual function inline is more a sign that the programmer a) doesn't understand virtual functions or b) forgot that the function is virtual. Both are bad.
    All the buzzt
    CornedBee

    "Writing specifications is like writing a novel. Writing code is like writing poetry."
    - Anonymous, published by Raymond Chen

    Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.

  20. #20
    Fanatic Member riis's Avatar
    Join Date
    Nov 2001
    Posts
    551
    At least I think you're right, NoteMe (but CB is the real expert, I'm just some wannabe ). If a function is made inline, then there's actually no function call. But, for implemented methods, derived from a base class with virtual methods, the methods should be stored in the v-table, so they cannot be made inline.

  21. #21
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594
    I was faster...
    All the buzzt
    CornedBee

    "Writing specifications is like writing a novel. Writing code is like writing poetry."
    - Anonymous, published by Raymond Chen

    Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.

  22. #22
    Fanatic Member riis's Avatar
    Join Date
    Nov 2001
    Posts
    551
    Yeah? Well, I don't smell it whether you're typing your answer in the same thread. It also happened in the "Construction error" thread.

  23. #23
    Retired G&G Mod NoteMe's Avatar
    Join Date
    Oct 2002
    Location
    @ Opera Software
    Posts
    10,191
    Thanks to both of you. Well can't see why sutch a hack should be applied anyway. And I was at least a bit right...

  24. #24
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594
    You were right for 99.9% of all cases.

    The hack was applied so that the backup version of the function (if a class didn't override it) could also be used for the case that no valid window handle was used.
    If would have been better (cleaner) to make the base version call a static member function, and use that static method for NULL pointers, too.
    All the buzzt
    CornedBee

    "Writing specifications is like writing a novel. Writing code is like writing poetry."
    - Anonymous, published by Raymond Chen

    Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.

  25. #25
    Retired G&G Mod NoteMe's Avatar
    Join Date
    Oct 2002
    Location
    @ Opera Software
    Posts
    10,191
    What about having a pointer in the base class, then a register function in the baseclass that the derived class could call to asign a pointer to a inlined function in the derived class...that would have been some hack....

  26. #26
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594
    Huh?
    All the buzzt
    CornedBee

    "Writing specifications is like writing a novel. Writing code is like writing poetry."
    - Anonymous, published by Raymond Chen

    Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.

  27. #27
    Retired G&G Mod NoteMe's Avatar
    Join Date
    Oct 2002
    Location
    @ Opera Software
    Posts
    10,191
    Forget what I said...when I was nearly finished explaining it I understood that I was making a VTable my self.......this can't be done at compile time, hence it can't be inlined....****...

    [ignore this start of the expleneation]
    Hehe...ok...let me try to explain a bit better. You have a base class A, and a derived class B. And you have a A-pointer pointing at a B object. You want to call a function in B that is inlined. But you can't do it because of the Vtable....what I was wondering if worked was you have a member-pointer in the Base class A, and a function that you can call registerFunction. Then when the derived object is made, it calls the function registerFunction from A, and sends a pointer to the function it wants to have inlined as a parameter.

    When the registerFunction gets called it assigns that pointer to it's member variable, so when you want to call the ......****...
    [/ignore this start of the expleneation]

  28. #28

    Thread Starter
    PowerPoster Halsafar's Avatar
    Join Date
    Jun 2004
    Location
    Saskatoon, SK
    Posts
    2,339
    Hey NoteMe thats thinking outside the box, which is why I enjoy C++ so much. I do believe what you are saying is possible. I do understand.

    When I first started c++ I figured pointers and references where useless and complicated......Now I find them to be the most powerful part of C++.

    Anyway, you are right about making an inline function virtual...I do not understand virtual functions very well.
    I must make my virtual function = 0 first off.

    In fact, with all this talk..I only faintly know what a V-Table is.
    I assume it is the "lookup" table, the compiler uses to manage either virtual calls, or everything..To keep things organized.

    Well thanks again, once more I still haven't had time to fix up my code, so I may still have more questions.
    "From what was there, and was meant to be, but not of that was faded away." - - Steve Damm

    "The polar opposite of nothingness is existance. When existance calls apon nothingness it shall return to nothingness." - - Steve Damm

    "When you do things right, people won't be sure if you did anything at all." - - God from Futurama

  29. #29
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594
    Your assumption is correct. Every class that has at least one virtual function has a vTable, which is just a list of pointers.
    One data member (I think usually the first, but this is compiler-dependent) of the class is the vPointer, which points to the vTable that this particular instance uses. While a normal function call is a jump to a specific address, a virtual function call is a lookup of the target address in the vTable. This is done by taking the vPointer and adding a function-specific offset to it. The result is dereferenced, and you have the target address.
    This additional dereferencing is called the virtual function call overhead and is the reason why you shouldn't use virtual functions when there's no reason to.
    All the buzzt
    CornedBee

    "Writing specifications is like writing a novel. Writing code is like writing poetry."
    - Anonymous, published by Raymond Chen

    Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width