Skip to main content
GameDev.net gamedev.net
🔒 Locked

C++ : creating 'devices'

Started by clapton Jan 22, 2007 at 2:32 PM 4 replies 900+ views
Original Post
clapton
clapton
Hello! I've been thinking for a couple of days on this one but I can't find an elegant solution. Assume that there is an interface class which specifies 'a device'. Most probably there are many particular device implementations. I am looking for a way to 'create a device' selected by the user while not requiring user to mess around with library code (i.e. no switch statement selecting an implementation). Here is what I'd like to achieve :

// We've got a pointer to a concrete device
deviceWin32::Device *pDevice;

// There is a global function (perhaps template?) which creates the device
// IMPORTANT : this should be the ONLY way to create device
createDevice<deviceWin32::Device>(pDevice);

// There is a global function which destroys the device
// IMPORTANT : this shoud be the ONLY wat to destroy device
destoryDevice<deviceWin32::Device)(pDevice);

The second major problem is - how to limit the code user to use only create/destroyDevice and forbid any other way of Device creation? One solution is to make createDevice/destoryDevice friend functions in deviceWin32::Device but it doesn't seem like an ideal solution. Thanks in advance!
___Quote: Know where basis goes, know where rest goes.
clapton
clapton
In the meantime, I came up with a following thing :

class IDevice{public:    virtual void CreateDevice(int width, int height, const char* pTitle) = 0;    virtual void DestroyDevice() = 0;protected:    ISSRDevice(){}    virtual ~ISSRDevice() {}};// createDevice/destroyDevicetemplate<class T> void createDevice(T* &pDevice, int width, int height, const char *pTitle){   pDevice = new T();   if (pDevice != NULL)   {	pDevice->CreateDevice(width, height, pTitle);   }}template<class T> void destroyDevice(T* &pDevice){   if (pDevice != NULL)   {	pDevice->DestroyDevice();	delete pDevice;	pDevice = NULL;   }}// now the implementation class Device :	public ISSRDevice{   // This two must be included in device implementation class   friend void createDevice<SSRDevice>(SSRDevice* &pDevice, int width, int height, const char* pTitle);   friend void destroyDevice<SSRDevice>(SSRDevice* &pDevice);public:   void CreateDevice(int width, int height, const char* pTitle) {}   void DestroyDevice() {}protected:   Device() {}   Device(Device&) {}   virtual ~Device() {}   Device& operator=(Device&) {};}


And here is how I use this stuff :

win32::Device *pDevice;createDevice<win32::Device>(pDevice, 640, 480, "window name");destroyDevice<win32::Device>(pDevice);


What do you think ? :F
___Quote: Know where basis goes, know where rest goes.
Anon Mike
Anon Mike
In general you need to have the caller supply you with some sort of token that indicates the particular type of device. There are two basic kinds of tokens.

The first is abstract ones such as id's, names, etc. In this model you either need a hardcoded switch which you say you don't want or a way for a manager to dynamically discover what sort of devices there are. This can be done directly by having each individual device type register with the manager or indirectly by having the device types leave registration information in some well known place (ini file, registry, etc).

The second approach is for the caller to give you the type in a more direct fashion. e.g. prototype device, template magic, etc.

For the enforcement issue I like to use static member functions to do my creating. It means you can't say "new Whatever()" and arrays are annoying but for the kind of things I go through this sort of effort for I don't care either. For distruction I tend to use ref counting and have objects that destroy themselves rather than explicit delete functions.
-Mike
clapton
clapton
Hi!

Quote:
Original post by Anon Mike
This can be done directly by having each individual device type register with the manager

This one sounds interesting. You mean there is a way to make device-classes register automatically? Or someone needs to do that manually?

Quote:

For the enforcement issue I like to use static member functions to do my creating. It means you can't say "new Whatever()" and arrays are annoying but for the kind of things I go through this sort of effort for I don't care either.

I tried to make a use of static methods but then I discovered that you obviously can't have virtual static methods. ;) More, I didn't want anyone who implements 'a device' to add any methods that are not listed in the interface (!). The solution (your post above) is that device implementation require CreateDevice and DestroyDevice but the only way to invoke these methods from outside the class is to use template functions. Perhaps I made it over-complicated but it works fine. If you see any drawbacks with the solution, please let me know.

Quote:
For distruction I tend to use ref counting and have objects that destroy themselves rather than explicit delete functions.

Yeah, I've been thinking on it but since I can't understand it clearly I decided not to use reference counting. I guess that rc concerns dynamic allocation only?

What I am trying to do is to make a simple abstraction for rendering system. Depending on the platform, user will switch 'devices' (win32 + BGI, win32 + DDraw, lin + SDL ... ) while the actual renderer would stay untouched.

Thanks for your help
___Quote: Know where basis goes, know where rest goes.
Anon Mike
Anon Mike
Quote:
Original post by clapton
Quote:
Original post by Anon Mike
This can be done directly by having each individual device type register with the manager

This one sounds interesting. You mean there is a way to make device-classes register automatically? Or someone needs to do that manually?

You eventually will need to do something manually. In this case typically what you would do is in your initialization code you tell each device type register itself. Then later on when the user gets around to asking for a device you have a list you can run through. You can minimize the amount of manual stuff you need to do by creating a device registration class that does the dirty work.

I don't know why you want virtual static functions for. What I usually do is to pass the registration function my token (device name or whatever) and a function pointer to the device-specific creation function. The global creation function then takes a token, looks up the cooresponding device-specific function and calls it to do the actual work.
-Mike
clapton
clapton
Quote:
Original post by Anon Mike
You eventually will need to do something manually. In this case typically what you would do is in your initialization code you tell each device type register itself. Then later on when the user gets around to asking for a device you have a list you can run through. You can minimize the amount of manual stuff you need to do by creating a device registration class that does the dirty work.

Ok, I get it. Actually it is pretty easy to do.

Quote:
I don't know why you want virtual static functions for.

I simply wanted to keep the global device-creating function within the class of the device. Just trying to minimize the amount of global stuff.

Thanks

___Quote: Know where basis goes, know where rest goes.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.