Ugly C looking code

J

Jim Langston

I've been working on a project to map a MySQL database to a C++ class.
Well, I actually got it to work, but some if it I just feel is exceptionally
ugly. For example, in my operator<< override:

template<typename T>
CMySQLTable& operator<<(const T& ClassTable)
{
/**/
}

I have a switch statement and code that looks like this:

switch ( ThisField.FieldType() )
{
case SQL_FieldType_Unknown:
std::cerr << " SQL_FieldType_Unknown: Error!" << std::endl;
assert(false);
break;

case SQL_FieldType_VarChar:
ThisField = *reinterpret_cast<const std::string*>( reinterpret_cast<const
char*>( &ClassTable ) + ThisOffset.Offset );
break;

case SQL_FieldType_Int:
ThisField = *reinterpret_cast<const int*>( reinterpret_cast<const
char*>( &ClassTable ) + ThisOffset.Offset );
break;

case SQL_FieldType_UnsignedInt:
ThisField = *reinterpret_cast<const unsigned int*>(
reinterpret_cast<const char*>( &ClassTable ) + ThisOffset.Offset );
break;

case SQL_FieldType_Bool:
ThisField = *reinterpret_cast<const bool*>( reinterpret_cast<const
char*>( &ClassTable ) + ThisOffset.Offset );
break;

/**/
}

It's the complicated casts that I find ugly. And in the operator>> override
it's just as bad, if not worst.

template<typename T>
CMySQLTable& operator>>(T& ClassTable)
{
/**/
}

switch ( ThisField.FieldType() )
{
case SQL_FieldType_Unknown:
std::cerr << " SQL_FieldType_Unknown: Error!" << std::endl;
assert( false );
break;

case SQL_FieldType_VarChar:
*reinterpret_cast<std::string*>( reinterpret_cast<char*>( &ClassTable ) +
ThisOffset.Offset ) = ThisField.Value();
break;

case SQL_FieldType_Int:
*reinterpret_cast<int*>( reinterpret_cast<char*>( &ClassTable ) +
ThisOffset.Offset ) = StrmConvert<int>( ThisField.Value() );
break;

case SQL_FieldType_UnsignedInt:
*reinterpret_cast<unsigned int*>( reinterpret_cast<char*>( &ClassTable )
+ ThisOffset.Offset ) = StrmConvert<unsigned int>( ThisField.Value() );
break;

case SQL_FieldType_Bool:
*reinterpret_cast<bool*>( reinterpret_cast<char*>( &ClassTable ) +
ThisOffset.Offset ) = ThisField.Value() == "0" ? false : true;
break;
/**/
}

Can you think of a cleaner way to do this, or is this the way I'm stuck with
just because of what I'm doing (working with pointers and offsets).

What I'm doing, and it works in test, is I have a class include a subclass
in which I map the variables I want to pull from the database.

void CCharFieldMap::SetMap( CCharacter* Base )
{
SetBase( Base );
SetOffset( "Version", Base->Version );
SetOffset( "Name", Base->Name );
SetOffset( "Password", Base->Password );
SetOffset( "Avatar", Base->Avatar );
SetOffset( "Race", *reinterpret_cast<unsigned int*>( &Base->Race ) );
SetOffset( "Sex", *reinterpret_cast<unsigned int*>( &Base->Sex ) );
SetOffset( "GM", Base->GM );
/**/
}

My overrides for << and >> look at this instance that contains information
about the variables (Type of variable, offset into class) and transfer data
back and forth using the base address of the passed reference and the
offsets.

It's the only way I could find to do it, and right now it seems it will be
extremely easy to use for the user (me) for new classes. No longer do I
have to go through SQL schenanigans to pull data to/from databases, I can
simply do code like:

if ( ! PlayerTable.init( "192.168.1.100", "serpardum", "somepassword",
"abyssal", "players", 3307 ) )
{
std::cerr << "Initialization failed" << std::endl;
std::string wait;
std::getline( std::cin, wait );

return 1;
}

if ( ! PlayerTable.LoadTable( "Name", "Serpardum" ) )
{
std::cout << "Serpardum not found" << std::endl;
return 1;
}

PlayerTable >> Player;

which would open my MySQL database, load the record where the Name ==
Serpardum, and load it into my class.

I like it, but as I said, I find some of it ugly. Any suggestions?
 
I

Ian Collins

Jim said:
I've been working on a project to map a MySQL database to a C++ class.
Well, I actually got it to work, but some if it I just feel is exceptionally
ugly. For example, in my operator<< override:
Why don't you just save all the fields as strings and convert them as
required?
 
S

Serpardum

Ian said:
Why don't you just save all the fields as strings and convert them as
required?

I don't quite understand what you mean. All the fields are strings in
the CField class. The operator>> and operator<< overrides are doing
the conversion. So what did you mean beyond this?
 
S

Serpardum

Phlip said:
Why not store a table of pointers into the MySQL result itself, and fetch
them out on demand, typesafely?

Please explain? Currently when I read the table it goes into a CField
map which contains the string that MySQL returns and the data type. So
in my CMySQLTable class I have a map of <std::string, CField> with the
std::string being the field name, and CField being the value (as a
string) and data type as stored in MySQL.

Oh, I think I see what you are saying, and I even thought about this.
Instead of storing them as std::string in the CField, store them as the
data type itself. I couldnt' figure out a good way to do this in a
map. A union wouldn't work as the data would be different sizes. And
even if I used a union of pointers (pointing to std::string, int,
unsigned int, etc...) I would still wind up having to use a switch
based on type.

Even if I came up with a way to store the data as it's type
transparently, the only thing this would save me is not having to run
StrmConvert</* type */>( ) on the strings. I don't see how it could
save me on the casting into the class they're being loaded into.
 
I

Ian Collins

I don't quite understand what you mean. All the fields are strings in
the CField class. The operator>> and operator<< overrides are doing
the conversion. So what did you mean beyond this?
I might have misunderstood your code, I though you were converting each
field value in a result as it was copied.

Looking at my own MySQL wrappers, I do pretty much what Phlip said and
store the query result and use the subscript operator to index rows and
again within the row to access fields. The field access converts the
value to std::string on read and from the base type on write.
 

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,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top