Static class? [Archive] - C Board

PDA

View Full Version : Static class?


Bubba
12-21-2003, 02:29 AM
I'm currently working on mouse support for my tile engine and I've run into problems. The DirectInput object is one interface - created one time. The Mouse interface is as well but I'm deriving it from DirectInput. Problem is that when I create the mouse, keyboard, etc - I do not want to create another instance of DirectInput.

If I declare DXInput as static, will this work?
It seems that MSVC does not like that, but I thought this was possible with classes?


Here is my setup:

DXInput.h

#ifndef _DXINPUT_
#define _DXINPUT_

#define DIRECTINPUT_VERSION 0x0700
#include "dinput.h"

class DXInput
{
protected:
LPDIRECTINPUT lpdi;
public:
DXInput(HINSTANCE instance);
~DXInput(void) {if (lpdi) lpdi->Release();};
};

#endif


DXInput.cpp

#include "DXInput.h"

DXInput::DXInput(HINSTANCE instance)
{

if (FAILED(DirectInputCreate(instance,DIRECTINPUT_VER SION,&lpdi,NULL)))
{
//error
}
}


DXMouse.h

#ifndef _DXMOUSE_
#define _DXMOUSE_

#include "DXInput.h"

#define RMB 0
#define LMB 1
#define MMB 2

class DXMouse:public DXInput
{
LPDIRECTINPUTDEVICE lpdiMouse;
DIMOUSESTATE MouseState;
public:
DXMouse(void) {};
~DXMouse(void)
{
if (lpdiMouse) lpdiMouse->Unacquire();
if (lpdiMouse) lpdiMouse->Release();
}
void Query(void) {if (FAILED(lpdiMouse->GetDeviceState(sizeof(DIMOUSESTATE),(LPVOID)MouseS tate))) };
int CheckButton(int ButtonToCheck);
void Show(void);
void Hide(void);
DIMOUSESTATE GetMouseState(void) {return MouseState;};
};
#endif


DXMouse.cpp

#include "DXInput.h"
#include "DXMouse.h"

DXMouse::DXMouse(void)
{
if (FAILED(lpdi->CreateDevice(GUID_SysMouse,&lpdiMouse,NULL))
{
//error
}
if (FAILED(lpdiMouse->SetCooperativeLevel(MainWindow,DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))
{
//error
}
if (FAILED(lpdiMouse->SetDataFormat(&c_dfDIMOUSE)))
{
//error
}
if (FAILED(lpdiMouse->Acquire()))
{
//error
}
}

int DXMouse::CheckButton(int ButtonToCheck)
{
Query();
if (MouseState.rgbButtons[ButtonToCheck] & 0x80)
{
return TRUE;
} else return FALSE;
}


Any help would be appreciated. I really want the mouse to be accessible by everyone in the engine. Having to go through a bunch of inheritance crapola when the mouse is a pretty global object seems kinda dumb.

Right now the compiler is yelling at me about a default constructor for DXInput when I attempt to create the mouse - I understand why it's doing this, but I'm not sure about the best route to go in getting around it.

And hey, look, all that and no assembly at all.

glUser3f
12-21-2003, 05:19 AM
I had a similar problem when working on the design of my 3D engine, finally I decided to go with global variables, something like this:
//dxinput.h
//...
extern DXInput* gDXInput;
//..
when the engine starts, it creates gDXInput (among the others) and when it shuts down, gDXInput is deleted.
I highly recommend against static variables, you may end up with mysterious errors when shutting down, and later discover that some variables are deleted before others.

Fordy
12-21-2003, 06:35 AM
If you want 1 version of the DirectInput interface, and want it available across a number of different objects then you might want to lookup the singleton pattern.

It's kind of like a static global option, but with more control and you can also decide how the object should be created/destroyed. You basically give an object a private contructor and a static function to either create itself or pass a reference of itself. Then to access the object's reference, you call this function

I wont give you a simple example because there's lots of slighty different ways of doing it and it's well worth a read. Scott Meyers does some good work on it and there are a few resources on the web

pheer
12-21-2003, 06:40 AM
Deriving the mouseclass from the inputclass doesnīt seem like a good idea to me, since it as you said does create a new directinput object.

One way to deal with it could be to put the mouse and the keyboard class into the inputclass.

Another is to put a public function in the inputclass that returns the pointer to lpdi (which itself is a pointer). If you donīt want the function public declare it as private and make the mouse and keyboardclass friends to the inputclass.

Fordy
12-21-2003, 06:51 AM
I changed my mind about the example...here's a very quick rough example;


#include <iostream>

class SomeInterface
{
public:
void SomeFunc(){std::cout << "You made an interface call!!" << std::endl;}
};

class InterfaceSingleton
{
InterfaceSingleton()
{
try
{
lpsi = new SomeInterface;
std::cout << "**Object Created**" << std::endl;
}
catch(...)
{
//handle
}
}
~InterfaceSingleton()
{
delete lpsi;
std::cout << "**Object Dead**" << std::endl;
}
SomeInterface *lpsi;
public:
SomeInterface *GetInterface(){return lpsi;}
static InterfaceSingleton& GetSingleton();
};

InterfaceSingleton& InterfaceSingleton::GetSingleton()
{
static InterfaceSingleton is;
return is;
}


int main()
{
std::cout << "Before the call no object is created, now I make a call;" << std::endl;
InterfaceSingleton::GetSingleton().GetInterface()->SomeFunc();
std::cout << "I make a call again, but this time no new object" << std::endl;
InterfaceSingleton::GetSingleton().GetInterface()->SomeFunc();
std::cout << "This is after the calls are made. Now the compiler will destroy my singleton" << std::endl;
}

glUser3f
12-21-2003, 06:59 AM
singleton classes caused me a lot of troubles, I had several singleton classes, a texture manager, and a shader manager, shader manager needed texture manager for its operations, on shut down, and for some reason, texture manager destructor was always called before shader manager, later, when shader manager destructor was called, it caused acess violation because it tried to access texture manager.

This is why I recommend global pointers allocated with new.

Fordy
12-21-2003, 08:54 AM
Originally posted by glUser3f
singleton classes caused me a lot of troubles, I had several singleton classes, a texture manager, and a shader manager, shader manager needed texture manager for its operations, on shut down, and for some reason, texture manager destructor was always called before shader manager, later, when shader manager destructor was called, it caused acess violation because it tried to access texture manager.

This is why I recommend global pointers allocated with new.

And if you had reserched singletons more you would notice a number of models that allowed you to destroy each individual object at a time of your choosing.

That's why I recommended reading....there's good stuff out there on this subject

glUser3f
12-21-2003, 09:12 AM
Originally posted by Fordy
And if you had reserched singletons more you would notice a number of models that allowed you to destroy each individual object at a time of your choosing.

That's why I recommended reading....there's good stuff out there on this subject Hmm, there maybe a good way to destroy the instance when needed, but wouldn't a global variable make stuff much simpler?
I mean, which one do you prefer to access the instance:gDXInput->checkMouse();
orDXInput::getInstance()->checkMouse();on the other hand, singleton classes work better in projects with several developers.
so you choose...

Bubba
12-21-2003, 12:05 PM
Thanks all for your help. I'm leaning more towards simply making the LPDIRECTINPUT object global. I'm gaining nothing by placing it in a class and it really does not need to be encapsulated.

I will leave the mouse in a class but it will use the LPDIRECTINPUT global interface to DirectInput. Just seems simpler that way.

Probably going to do the same with my DirectSound interface.