Originally Posted by
Shamino
Why would I try to use a sound file as a text file ever?
Sounds like the code in question has a lot of pointers to the base class being passed around. Really, the only purpose of the base class is to let you stuff all these different types into the same map.
The basic architectural issue is, how do you get stuff out of the map in a type-safe way? If you design it so that the caller asks for something by name, and a base class pointer is handed back, you have the problem of determining what the actual type of that object is. But by accessing the database a different way you can get around this problem.
Instead of having the DB return a pointer, you call the lookup and pass it a pointer to an "acceptor" object which accepts the looked-up pointer via a function call. This leaves the decision about what type of object it is UP TO THE OBJECT ITSELF, because it will invoke the proper accept function on the acceptor object:
Code:
// abstract Acceptor base class -- classes interested in looking things up from a database
// will derive from this.
class Acceptor
{
public:
virtual ~Acceptor() { }
virtual bool acceptSound(DBSoundObject *ptr) = 0;
virtual bool acceptText(DBTextObject *txt) = 0;
};
// Database object base class -- all objects stored in the database derive from this and
// override the put() method to call the appropriate acceptor function.
class DBObject
{
virtual ~DBObject { }
virtual bool put(Acceptor *acc) { return false; }
};
class DBSoundObject : public DBObject
{
public:
bool put(Acceptor *acc)
{
return acc->acceptSound(this);
}
};
class DBTextObject : public DBObject
{
public:
bool put(Acceptor *acc)
{
return acc->acceptText(this);
}
};
Now, the things you store in the maps are shared pointers to DBObject objects. To do a lookup, you get the DBObject from the map, then you call its put() method and pass a pointer to the Acceptor object, i.e., the object which was trying to do the lookup.
Code:
DBObject *obj = some_map[some_string];
if(obj)
{
// Get the result and pass it to this, which accepts it with one of the various acceptor
// functions
obj->put(this);
}
Or, if you know for sure that obj will never come back null, the more compact:
Code:
some_map[some_string]->put(this);
It seems sort of roundabout, but you should be able to see that there is no way an object could ever be treated as the wrong type, because the object itself knows what its type is, and the object decides which accept() method to call on the Acceptor.
So you derive from Acceptor and override the various accept() functions to accept the lookup-up objects and do whatever needs to be done with them.