Thread: Creating a database

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968

    Creating a database

    So I'm making this class that is supposed to organize all the dynamic data I'm going to use in my game.

    It's basically yet another wrapper for a map wrapper class. Only this time we're going to globalize it and derive subclasses that load in each kind of data when called. I kindof want a centralized database though, so maybe I should instead create a manager inside of the database to manage all the other managers?

    It seems redundant to create a manager of managers in the database don't you think? Instead maybe there should be a database for each kind of dataset in the database class? But then again how would that be any different from having multiple global managers. I shouldn't put them in a database for the sake of keeping them local and not global instances.

    So then the database will of course load a dataset into each manager. So maybe the best thing to do is keep a container, perhaps a simple vector of manager classes. Therefore I can add a manager via function, as well as remove one.

    Then I would have to hardcode the data loading functions, actually, that isn't true! The resource manager is set up to create objects using an initializing variable, which can be fed information via binary or text file.

    So then all the functionality of the database can be in a function that loads data from a file, which then uses the proper manager.. wait how will it know? Then I'll just create a resource manager of resource managers to connect a string to each manager. Templates within templates, bwahaha i love oop. To load the files i'll pass it a string to search for a filename that will co ensign with the proper manager.

    Problem solved.

    Now to write it.

    Code:
    #ifndef DATABASE_H
    #define DATABASE_H
    
    #include "Resource_Manager.h"
    
    class Database
    {
    	
    	
    };
    
    #endif
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  2. #2
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    hm it seems C++ syntax won't let me create a template of templates....

    Code:
    Resource_Manager<Resource_Manager<T_>> Data;
    Code:
    c:\documents and settings\home\my documents\visual studio 2005\projects\textgame\textgame\database.h(9) : error C3203: 'Resource_Manager' : unspecialized class template can't be used as a template argument for template parameter 'T_', expected a real type
    Maybe a vector would work better.

    AHG a vector doesn't work either!!!
    Code:
    std::vector<Resource_Manager<T_>> Data;
    Did they like, fail to add this feature to C++ yet?

    Can't we keep templates in a container?
    Last edited by Shamino; 06-03-2007 at 09:42 PM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  3. #3
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Yes, you can. This compiles:
    Code:
    template <typename T>
    class something {
    public:
        something<something<T> > x;
        std::vector<something<something<something<T> > > > y;
    };
    I'm using Dev-C++ which employs g++.

    You must have some other problem. Can you post some more code?
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  4. #4
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Code:
    #ifndef DATABASE_H
    #define DATABASE_H
    #include <vector>
    
    #include "Resource_Manager.h"
    
    class Database
    {
    	
    	std::vector<Resource_Manager<T_>> Data;
    };
    
    #endif
    This is the code that is giving me that error...
    I tried this:
    Code:
    std::vector<Database<Database<Resource_Manager<T_>>>> Data;
    And it compiles, the question is, I'm having a real tough time understanding that syntax, what exactly is going on here?
    Last edited by Shamino; 06-05-2007 at 02:03 AM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  5. #5
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    http://www.open-std.org/jtc1/sc22/wg...005/n1757.html

    New release of gcc will have a fix for this

    std::vector<Resource_Manager<T_>> Data;

    What is _T?

  6. #6
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    T_ is the data type that the resource manager manages, since it can't keep a text file or a graphic file in the same std::map. It has to be specified on creation

    I want the Database to be responsible for creating resource managers.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  7. #7
    Massively Single Player AverageSoftware's Avatar
    Join Date
    May 2007
    Location
    Buffalo, NY
    Posts
    141
    As was pointed out earlier, if your Database class is going to contain a template with an undefined datatype, it must also be a template.

    Code:
    template <typename T_>
    class Database
    {
    	
    	std::vector<Resource_Manager<T_>> Data;
    };
    Also, if you don't have a compiler that had started to implement the C++09 standard, you probably need a space between the two >, like so:

    Code:
    std::vector<Resource_Manager<T_> > Data;
    There is no greater sign that a computing technology is worthless than the association of the word "solution" with it.

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    First of all Shamino I applaud your efforts and your willingness to listen to advice. You have come a very long way in a very short time on this board and in your code.

    In this instance I feel that you may be trying to be too, shall we say, C++'ey? I never did like the template idea and I think I made that known but I also realize that you are a person that has to try out an idea and research it before deciding if you like it or not. There is nothing wrong with that and that is how I learn as well. Here I think you have come to a place in your template approach that is extremely flawed and perhaps should re-think the entire system.

    I almost tried your template idea and then realized what a mess it would be later when I needed to determine object types. Yes there are ways in C++ to do that but I feel there is a much better approach. The approach I took to this comes from my experience with COM programming.

    In COM programming everything is derived from IUnknown which implements a few very simple interfaces. So allow me to show my implementation of the objects and managers and go through the problem logically.

    What both of us are trying to do is create a centralized way of creating, accessing, storing, and destroying objects. The problem is that not all of our objects fit into a nice neat little mold and each have their own quirks. But in the bigger picture we are simpy storing objects.

    So a generic, non-specific manager or container base class will at the very least have:

    1. Have a method to create or add an object to the container and maybe return an ID.
    2. Have a method to delete or remove an object from the container.
    3. Have a method to gain access to an object via the ID returned in item 1 or upon creation.
    4. Have a method to return the number of objects in the container or the object count.
    5. Have a method to store the objects to disk.
    6. Have a method to read the object from disk.

    Classes derived from this base can then implement object-specific functions relative to the type of object they contain. But all container classes will at the very least inherit items 1 through 4. If we make the base too complex we will end up making it object specific and therefore will code ourselves into a corner when trying to add different objects.

    Now at the very least a generic, non-specific object base class will:

    1. Have a method to create the object.
    2. Have a method to access the object.
    3. Have a method to delete the object.
    4. Have a method to store the object to disk.
    5. Have a method to read the object from disk.

    Now for specific objects we derive from the base object class and implement other functions specific to the type of object.

    Now thanks to C++ polymorphism we can do this:

    Code:
    class CObject
    {
       ...
    };
    
    class CObjectMgr
    {
       std::vector<CObject *> m_vObjects;
    
       public:
          DWORD Add(CObject *pObject)
          {
             m_vObjects.push_back(pObject);
             return static_cast<DWORD>(m_vObjects.size()-1);
          }
          
    
    };
    Now as long as the object we want to add is derived from CObject we can pass this to the container base class Add() function and it will work perfectly. My system has the main list or vector in the base container class and all access to and from it is through the container class. The base class is then responsible for destroying the object.

    This is a very simple system but it works well for me. Sorry the post is so long but it is hard to talk about generic container class programming in short posts.

  9. #9
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Hmm

    Your non specific manager class sounds alot like this:
    Code:
    #ifndef RESOURCE_MANAGER_H
    #define RESOURCE_MANAGER_H
    #pragma warning(disable: 4786)
    #pragma warning(disable: 64)
    #include <vector>
    #include <map>
    #include <string>
    #include <boost\shared_ptr.hpp>
    #include <boost\weak_ptr.hpp>
    #include <iostream>
    
    template< typename T_ >
    class Resource_Manager
    {  
    
    public:
    
    	typedef T_ value_type; // std library convention 
    
    	typedef boost::shared_ptr<T_> Resource_Ptr;
    	typedef boost::weak_ptr<T_> Resource_Observer;
    	typedef std::map< std::string, Resource_Ptr > Resource_Map;
    
    	Resource_Manager<T_>() {};
    	~Resource_Manager<T_>() {};
    
    	void Add_Resource(const std::string & name, T_)
    	{
    		Resource_Ptr Raw_Resource(T_);
    		mResources.insert(std::make_pair(name, Raw_Resource));
    	}
    
    	Resource_Observer Request_Resource(const std::string & name)
    	{
    		Resource_Map::iterator  it = mResources.find(name);
    
    		if (it == mResources.end())
    		{
    			std::cout << "Internal program error, " << name << " does not exist!" << std::endl;
    		}
    		else
    		{
    			return Resource_Observer(it->second);
    		}
    	}
    
    	void Request_Resource_Removal(const std::string & name)
    	{
    		Resource_Map::iterator it = mResources.find(name);
    
    		if (it != mResources.end())
    		{
    			mResources.erase(it);
    		}
    	}
    
    private:
    	Resource_Map  mResources;
    };
    
    #endif
    I have 1-4 covered...


    The only thing is we aren't storing a generic object we're storing an actual type determined by me. But in reality they are all objects to store, so you're right there. If I did it your way, it looks like I'd have different kinds of managers for each type of object we're using. But it's funny because they all are objects, but we still can't put them in the same box, I guess it makes sense though, because object is such a generic term. The same would be for my templated resource manager. The question in the end is really which is easier to organize into a master database class?

    So far I've been failing with my template, but thats just because I've been trying to throw them all in the same container, which is impossible with both methods. I think I will still use boost in my managers, it allows for easy dynamic memory. I'll probably have to cut the map down to a vector, actually I don't see why I shouldn't keep it. It seems pretty useful to have a string connected to each type of data.

    I like your method better to be honest, it makes more logical sense. But my question still, is how do I centralize it into a Database class?
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  10. #10
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    The manager has been converted!

    Code:
    class Object_Manager
    {  
    public:
    
    	Object_Manager() {};
    	~Object_Manager() {};
    
    	typedef boost::shared_ptr<Object> Object_Ptr;
    	typedef boost::weak_ptr<Object> Object_Observer;
    	typedef std::map< std::string, Object_Ptr > Object_Map;
    
    	void Add_Object(const std::string & name, Object * CObject)
    	{
    		Object_Ptr Raw_Object(CObject);
    		mObjects.insert(std::make_pair(name, Raw_Object));
    	}
    
    	Object_Observer Request_Object(const std::string & name)
    	{
    		Object_Map::iterator  it = mObjects.find(name);
    
    		if (it == mObjects.end())
    		{
    			std::cout << "Internal program error, " << name << " does not exist!" << std::endl;
    		}
    		else
    		{
    			return Object_Observer(it->second);
    		}
    	}
    
    	void Request_Object_Removal(const std::string & name)
    	{
    		Object_Map::iterator it = mObjects.find(name);
    
    		if (it != mObjects.end())
    		{
    			mObjects.erase(it);
    		}
    	}
    private:
    
    	Object_Map  mObjects;
    };
    Last edited by Shamino; 06-10-2007 at 12:57 AM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  11. #11
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    The only thing I'm curious about, the Object base class, does it have nothing but empty virtual methods in it? It seems to me that every single object is different in every aspect 1-5.

    Code:
    class Object
    {
    	virtual void Create()
    	{}
    	virtual void Access()
    	{}
    	virtual void Delete()
    	{}
    	virtual void Read_File(std::string Filename)
    	{}
    	virtual void Save_to_File(std::string Filename)
    	{}
    };
    Last edited by Shamino; 06-10-2007 at 12:15 AM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  12. #12
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Actually the object base class implements all of its methods to the best of it's ability.

    I have encountered the same problem you have in my system at times. Let's say I have materials for objects. The material properties applied to an object determine how light interacts with the object. This is a resource but it is an engine resource not a game resource. So the first derivation of objects is just that. I have resource objects and then game objects. Keeping the two separate has been much easier than lumping them together.

    Now I know this means you will have 2 derivations before you actually get to the specific objects, but it makes things a lot easier conceptually and architecturally. I hate having 2 derivations but I've not found a good way to get around it.

    So in short my core engine setup:

    Engine architecture
    Resources
    • CResource - Resource base class
    • CMaterial - (D3DMATERIAL9)
    • CShader - (ID3DXEffect)
    • CLight - (D3DLIGHT9)
    • CTexture - (IDirect3DTexture9)
    • CD3DXMesh - (ID3DXMesh)
    • CD3DXProgMesh - (ID3DXPMesh)
    • CAnimFrame - animation frame class

    Resource managers
    • CResMgr - Resource manager base class
    • CMatlMgr - Materials manager
    • CShaderMgr - Shader manager
    • CLightMgr - Light manager
    • CTexMgr - Texture manager
    • CD3DXMeshMgr - Model mesh manager
    • CD3DXProgMeshMgr - Model progressive mesh manager
    • CAnimSeq - animation sequence class - animation frame container class


    Sound engine resources
    • CDXSoundSegment - (IDirectMusicSegment8,IDirectMusicSegmentState8)
    • CDXAudioPath - (IDirectMusicAudioPath8)
    • CDXSoundEmitter - container class for sound segments - each emitter can have any number of sounds associated with it and each play on separate audio paths


    Script support
    • ScriptCmn.h - script support common header file
    • CScriptVarMgr - Script variable container class


    Utility classes
    • CCamera - 3D camera support (cockpit/first person, chase, object, flyby, and free floating camera support)
    • COrient3D - controls all 3D orientations for all objects
    • CINIReader - reads ini files in form [Header] Key=Value
    • CTimer - timer class


    Engine objects (non-game specific)
    • CSkyBox - skybox support
    • CBillboard - billboarding support
    • CSprite - sprite class (uses a CAnimSeq)
    • CSkySphere - spherical skybox support (also textured sphere support)


    Core engine classes
    • CD3DApp - Direct3D application base class
    • CD3DView - Direct3D view class (not quite implemented fully)
    • CDXAudio - DirectMusic base class
    • CDXInput - DirectInput base class
    • CDXShowWnd - DirectShow base class
    • CKeyboard - keyboard device class
    • CMouse - mouse device class
    • CGamePad - stick/pad device class


    Debug
    • CEngineException - exception handling class
    • CMemCheck - memory checking class (not fully implemented)


    This is a small list of the basic engine classes. An actual game coded with the engine would have many more object and game specific classes.

    I'm not sure what you mean by a database but since all of my base classes can stream to disk, all of the derived classes inherit that support and/or can override the base implementation if needed.

    Either you are going to create tons of template classes for managers or you are going to create tons of separate manager classes. Either way all objects cannot just be lumped into one huge container because they are so different from one another. My actual game code classes for my space project and for the Zelda project are also quite numerous but they derive from these. This is what I would consider my core engine code and I would like to keep it separate from game specific data and objects.

    I was going to create a memory and file resource class but found that both of those were so simple they were not needed. Plus any memory class I come up with is probably not going to be faster than just using new and delete.
    I also wanted to create an archive class but it proved to be a bit more difficult than I first thought.

    The simple way to do object serialization is to take the MFC approach. If your base resource class has a Serialize() function or WriteToDisk() ReadFromDisk() then you can just make it a pure virtual. This means it will have to be implemented in derived classes and you cannot instantiate the base. Since the base object has no way of knowing how to write the object to disk I recommend this approach. So in your derived classes you simply code the virtual function specific to your object.

    Code:
    
    ...
    CShipMgr *pShipMgr=new CShipMgr();
    pShipMgr->AddFromINI(m_spDevice,"INI\\Ships\\Ships.ini","Terran")
    CArchiveFile *pFile=new CArchiveFile("TerranShips",WRITE_ONLY);
    CArchiver *pArchive=new CArchiver(pFile,CArchiver::WRITE);
    pShipMgr->Serialize(pArchive)
    
    ...
    ...
    
    //CShipMgr derived from CResMgr which has pure virtual Serialize(CArchiver *pArchiver)
    void CShipMgr::Serialize(CArchiver *pArchiver)
    {
      if (pArchiver->IsStoring())
      {
         //Write data to stream
      }
      else
      {
         //Read data from stream
      }
    }
    As I said this is not quite complete yet since CArchiver has been proving to be a pain in the rump.
    Last edited by VirtualAce; 06-10-2007 at 01:32 AM.

  13. #13
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    I see, well I wonder...

    With the create method in the object base class, what can we possibly implement when we don't know what kind of data the object stores?

    Like you were saying, when you create a new object it could be a material, or a mesh, or a sound.. Each of these objects have completely different variables and such, like vertices or a sound file... or lighting details... They have absolutely nothing in common.. What could I implement in the create function that would be universal to all objects?

    The same goes for the delete method. Perhaps we can access all of the objects via pointer, but that is also handled by the manager class, it returns a pointer to a raw object.

    Unless the access method is ment to return the data contained in each specific object class, such as an array of vertices or something like that, which would be useful. So then again none of that data is ever the same, none of it is in common. Really only the abstract idea of the methods in the object base class are the same.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Create would be virtual. Implement it in the derived object classes. You could implement creation in the constructor but then you get into lots of exceptions being thrown but it does follow RAII.

    You are creating interfaces for your derived objects. This ensures that your derived objects implement some type of standard interfaces/functions for each object and manager. These are not interfaces such as COM interfaces but the principle is somewhat the same.

  15. #15
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    I guess the only problem now is making it so my objects can be serialized and deserialized. Especially Menu objects.

    But that post is in the C++ forums.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. literature database: help with planning
    By officedog in forum C++ Programming
    Replies: 1
    Last Post: 01-23-2009, 12:34 PM
  2. Profiler Valgrind
    By afflictedd2 in forum C++ Programming
    Replies: 4
    Last Post: 07-18-2008, 09:38 AM
  3. Creating a database (inside a GUI)
    By goosematt in forum C Programming
    Replies: 7
    Last Post: 10-23-2003, 11:04 AM
  4. Creating a simple database: is my approach OK?
    By m712 in forum C++ Programming
    Replies: 1
    Last Post: 11-18-2002, 02:27 AM
  5. creating a small database need some hints
    By asim0s in forum C++ Programming
    Replies: 1
    Last Post: 02-28-2002, 10:44 AM