design guidance .. I'm confused

M

ma740988

I've provided a stripped down version - as best I could - to get us by.
That said, I'm in a quandry with respect to a design here.

Consider:
// stream.h
#ifndef STREAM_H
#define STREAM_H

# pragma warning (disable : 4786) // if using microsofts compiler ver6

# include <iostream>
# include <string>
# include <map>
# include <typeinfo>

using namespace std;

struct stream
{
string classId;
string buffer;
size_t curPos;

stream(string clsId)
: classId(clsId), curPos(0)
{}

stream(char* buf, size_t size)
: curPos(0)
{
string temp(buf, size);
size_t pos = temp.find(':');
if (pos == string::npos || pos == 0 || pos == size-1)
return;
classId = temp.substr(0, pos);
buffer = temp.substr(pos+1);
}

bool isValid() { return curPos <= buffer.length(); }
operator bool() { return isValid(); }

size_t getBufferSize() {
return isValid()? classId.size() + 1 + buffer.size() : 0;
}

size_t getBuffer(char*& buf, size_t siz)
{
size_t sizNeeded = getBufferSize();
return sizNeeded;
}
};


template <class T>
inline stream& operator>>(stream& ds, T& t) {
// stuff
return ds;
}
template <class T>
inline stream& operator<<(stream& ds, T& t) {
// stuff
return ds;
}
// more
#endif

// factory.h
#ifndef FACTORY_H
#define FACTORY_H

# include<map>
# include<string>
# include "stream.h"

class factory;
typedef factory* (*CreateInstanceFunc)();
struct stream;
using namespace std;
class factory
{
// factory map is mapping class names to create functions
static std::map<std::string, CreateInstanceFunc> factoryMap;
public:
virtual std::string getClassId() = 0;
virtual bool load(stream& ds) = 0;
virtual bool store(stream& ds) = 0;
virtual void execute() = 0;
static factory* createInstance(const stream& ds)
{
map<string, CreateInstanceFunc>::iterator it;
if ((it = factoryMap.find(ds.classId)) == factoryMap.end())
return NULL;
return (it->second)();
}

static bool registerClass(
const std::string& className,
CreateInstanceFunc createFunc
)
{
map<string, CreateInstanceFunc>::iterator it;
if ((it = factoryMap.find(className)) != factoryMap.end())
return false; // already registered

factoryMap[className] = createFunc;
return true;
}

stream* store();
};

std::map<string, CreateInstanceFunc> factory::factoryMap;

#endif

// now we're ready file: test.cpp
# include <iostream>
# include <string>
# include "factory.h"
# include "stream.h"

using namespace std;

struct test_struct
: public factory
{
int idx;
test_struct() : idx(99) {}

std::string getClassId() {
return "test_struct";
}
bool store(stream& ds) {
ds >> idx;
return ds.isValid();
}
bool load(stream& ds) {
ds << idx;
return ds.isValid();
}
static factory* create_msg () {
return new test_struct;
}
void execute () {
}
};

/////////////////////////////////////////////////////////////////
// the registration below is REALLY bad news. Need to rethink this
// static initilization order stuff.
//factory::registerClass("test_struct", test_struct::create_msg);
class test {
test_struct* ptr_msg;
public:
test() : ptr_msg(0) {
factory::registerClass("test_struct", test_struct::create_msg);
}
void get_data()
{
char buffer[4096] = { "test_struct:99" };
size_t len = sizeof buffer / sizeof *buffer;

stream st (buffer, len);
if (st)
{
ptr_msg = (test_struct*)factory::createInstance(st); // 99
if (ptr_msg != NULL)
{
cout << " success " << endl;
if (ptr_msg->idx == 99)
cout << " even more success " << endl;
}
}
}
};

int main()
{
test t;
t.get_data();
}

The line marked '99' is a cast from a polymorphic type to a test_struct
object. So I thought it would nice to eliminate that ugly cast, hence
the addition of the 'execute' function in persistent.

Trouble is, the execute function creates a problem for two reasons:
1. I could modify the source in get_data to look like:

if (st)
{
//ptr_msg = (test_struct*)factory::createInstance(st);
factory* pfact = factory::createInstance(st);
if (pfact != NULL)
{
cout << " success " << endl;
pfact->execute();
//if (ptr_msg->idx == 99)
// cout << " even more success " << endl;
}
}
Except now I need a way to move from the factory object to a
test_struct object so that I could do:
if (ptr_msg->idx == 99)
// do a special thing.

One thought was to modify execute in the test_struc class to look like:
void execute () {
t.update(this); // call some update function in test
}

Trouble is. I now need a 'global' initilization of t. Not good. It
gets worse. In my real code, the initilization of t is wrapped in a
try catch handler so that there goes the global initilization.

2. In theory my 'struct's are defined as incoming and outging msg
structs. So now:

struct outgoing_msg
: public factory
{};

struct incoming_msg
: public factory
{};


The only struct that needs to go through these 'hoops' is the
incoming_msg struct. That said, I would have an execute member
function in the outgoing_msg struct for NO reason.

In the end I suspect I'm just forced to live with the cast from a
polymorphic object to a test_struct.

ptr_msg = (test_struct*)factory::createInstance(st);

Thoughts/ideas?

Thanks in advance
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top