Abstraction? Nevermind, I think I got it


kuru

Laptop und Trachtenjanker
Joined
Oct 8, 2008
Messages
3,291
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:
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
 
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.
 
Code:
WindowManager::WindowManager()
{
    //Konstruktor
    this->Create();
}

WindowManager::~WindowManager()
{
    //Destruktor
    this->Destroy();
}
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!

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?

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;
}
 
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
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:
Back
Top