1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Dismiss Notice

Abstraction? Nevermind, I think I got it

Discussion in 'C /C ++' started by kuru, Dec 19, 2016.

  1. kuru

    kuru Irate Pyrate

    Joined:
    Jan 13, 2009
    Messages:
    1,471
    Location:
    the mockracy
    Tutorials say you should prescind code and put it in a file of its' own, encapsulate it according to its' function.
    So the noob looks at their main.cpp and tries to move everything SDL-specific to another file like I did below.

    But you will find SDL_Window* in main.cpp. I guess this works because WindowManager.h and .cpp both include SDL.h.
    SDL_Window* should not be in main.cpp, correct?

    What is the proper thing to return from WindowManager::Create() ?
    I tried getting a memory address which to then be able to feed to WindowManager:: Destroy() but got completely lost in details. Would I have to know the size of the memory being pointed at to do this properly?
    or
    Am I overthinking? Is there a more elegant way? Maybe just returning TRUE from WindowManager::Create() and having some invisible variable inside the WindowManager object store the pointer-to-surface? What's the 'proper' way to do that?

    Do I even need to include WindowManager in main, or can this be done with a forward declaration?

    Please excuse my throwing around big words paired with a tremendous lack of insight! The truth seems within arm's reach...
    main.cpp
    Code:
    #include "WindowManager.h"
    
    int main( int argc, char* args[] )
    {
    
        WindowManager MyWindowManager;
        SDL_Window* GameWindow = MyWindowManager.Create();
        MyWindowManager.Destroy(GameWindow);
    
        return 0;
    }
    
    the pretentiously named WindowManager.cpp
    Code:
    
    SDL_Window* WindowManager::Create()
    {
        //The window we'll be rendering to
       SDL_Window* window = NULL;
    
       //The surface contained by the window
       SDL_Surface* screenSurface = NULL;
    
       //Initialize SDL
       if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
       {
    
           printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
       }
       else
       {
           //Create window
           window = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
           if( window == NULL )
           {
               printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
           }
           else
           {
               //Get window surface
               screenSurface = SDL_GetWindowSurface( window );
    
               //Fill the surface white
               SDL_FillRect( screenSurface, NULL, SDL_MapRGB( screenSurface->format, 0xFF, 0xFF, 0xFF ) );
    
               //Update the surface
               SDL_UpdateWindowSurface( window );
    
               //Wait two seconds
               SDL_Delay( 2000 );
    
               return window;
    
           }
    
       }
    printf( "WindowManager problems");
    return NULL;
    }
    
    void WindowManager::Destroy(SDL_Window* window)
    {
        //Destroy window
       SDL_DestroyWindow( window );
        printf( "Window has been destroyed\n");
    
       //Kill SDL
       SDL_Quit();
       printf( "SDL has been quit\n");
    }
    
    


    Edit:
    I've changed my main.cpp as follows:
    Code:
    int main( int argc, char* args[] )
    {
    
        WindowManager MyWindow;
        MyWindow.Create();
        MyWindow.Destroy(MyWindow.WindowHandle);
    
        return 0;
    }
    
    WindowHandle is a public variable of type SDL_Window* inside WindowManager
    Is that what abstraction is all about? Explicitely not having written down the SDL_Window type in this file? Or am I violating the principle just by having the type occur in this file?

    Edit2:
    Meh! I don't need to pass the WindowHandle to the destroy method within main.cpp.
    Code:
    int main( int argc, char* args[] )
    {
    
        WindowManager MyWindow;
        MyWindow.Create();
        MyWindow.Destroy();
    
        return 0;
    }
    

    It's better to let the handle be a private variable in WindowManager.cpp that I can simply reference from there.
    Code:
        private:
            SDL_Window* WindowHandle;
    
    //and
    
    void WindowManager::Destroy()
    {
        //Destroy window
       SDL_DestroyWindow( WindowHandle );
        printf( "Window has been destroyed\n");
    
       //Kill SDL
       SDL_Quit();
       printf( "SDL has been quit\n");
    }
    
    Whaddayasay? I think I got it now. Writing down some thoughts helped.
     
    Last edited: Dec 19, 2016
    Tags:
  2. Nilsnsn

    Nilsnsn Member

    Joined:
    Jun 3, 2012
    Messages:
    66
    Location:
    Braunschweig
    if you declare your constructor and destructor as
    Code:
    WindowManager::WindowManager()
    {...}
    
    WindowManager::~WindowManager()
    {...}
    
    you can cut your main function to

    Code:
    int main( int argc, char* args[] )
    {
    
       WindowManager MyWindow;
    
       return 0;
    }
    
    And "create" and "destroy" will be called automatically
     
  3. kuru

    kuru Irate Pyrate

    Joined:
    Jan 13, 2009
    Messages:
    1,471
    Location:
    the mockracy
    Constructor and destructor were declared explicitely but it wouldn't work. I had an inkling that {...} would have to say something sensible to make the magic you mentioned happen. Now I know what "this" is for!
    Code:
    WindowManager::WindowManager()
    {
        //Konstruktor
        this->Create();
    }
    
    WindowManager::~WindowManager()
    {
        //Destruktor
        this->Destroy();
    }
    
    I understand that the constructor is being called because an object is created.
    Reading some more tells me the destructor gets into play once the lifetime of the object has ended.
    What determines the end of the object's lifetime?

    The example code I'm reading has obscure syntax, only making things harder.
     
  4. Nilsnsn

    Nilsnsn Member

    Joined:
    Jun 3, 2012
    Messages:
    66
    Location:
    Braunschweig
    Actually i meant to put the code of Create in the constructor and Destroy in the destructor, but this is also viable. Sorry for not being clear enough!

    If you initialize it as a pointer like:
    WindowManager* wm = new WindowManager();
    Then the lifetime ends when you call:
    delete wm;

    If you declare it as a variable like:
    WindowManager wm;
    Then the lifetime ends when the block in which it is declared ends, which can be the function or even at the end of an if-statement
    Code:
    function xyz()
    {
      if (condition)
      {
        WindowManager wm;
        instructions;
      }  //Lifetime of wm ends with this bracket
      instructions;
    }
    
     
  5. kuru

    kuru Irate Pyrate

    Joined:
    Jan 13, 2009
    Messages:
    1,471
    Location:
    the mockracy
    That fills in the blanks, thanks for elaborating!

    Edit:
    To keep my train of thought going, here's some information on pointers vs. variables. Not exactly easy to read, but encompassing.

    Edit:
    1. Do not use arrays. Work with std::vector instead. Chairs are comfier than nailbeds.
    2. Remember what the keyword extern does.
    3. Use include guards.
     
    Last edited: Dec 29, 2016
    Nilsnsn likes this.

Share This Page

Loading...