C++ design problem involving unions

A

Angus

Hello

I am modelling a telephony item, called a connection id, which is made
up of two components. A thing called a Call id and a device id. Both
the Call ID and the Device ID could be either a string or a integer.

My initial design used a union to store the data (a union was used for
performance/code size reasons over templates). Here is a rough
outline of the code:

class ConnectionID : public ref_type
{
public:
typedef ref_ptr<ConnectionID> ptr_type;
ConnectionID();
ConnectionID(int callid, int deviceid);
ConnectionID(int callid, const char* szDeviceID);
ConnectionID(const char* szCallID, int deviceid);
ConnectionID(const char* szCallID, const char* szDeviceID);
~ConnectionID();

enum DataType { type_none, type_int, type_charp };

//CallID
string getCallID(string& callid) const;
long getCallID(long callid) const;
void setCallID(const char* callid);
void setCallID(long callid);
DataType getCallIDType() const;

//DeviceID
string getDeviceID(string& callid) const;
long getDeviceID(long devid) const;
void setDeviceID(const char* devid);
void setDeviceID(long devid);
DataType getDeviceIDType() const;

protected:
union{
long nCallid;
char* szCallid;
}m_callid;
DataType m_CallIDType;

union{
long nDeviceID;
char* szDeviceID;
}m_DeviceID;
DataType m_DeviceIDType;
};

///Device
class DeviceID : public ref_type
{
public:
typedef ref_ptr<DeviceID> ptr_type;
DeviceID();
DeviceID(int deviceid);
DeviceID(const char* szDeviceID);
~DeviceID();

enum DataType { type_none, type_int, type_charp };

//DeviceID
string getDeviceID(string& devid) const;
long getDeviceID(long devid) const;
void setDeviceID(const char* devid);
void setDeviceID(long devid);
DataType getDeviceIDType() const;

protected:
union{
long nDeviceID;
char* szDeviceID;
}m_DeviceID;
DataType m_DeviceIDType;
};

You cannot use a class with a constructor with a union so that is why
I used a char*.

What I would like to do is somehow hide the union and allow users to
set and get using either a std::string or an int. I have other places
where a union with other types are required and using class objects
would be more convenient.

How could I hide the union/char* implementation from the user of the
class? But still benefit from the union?

Any assistance would be most appreciated.

Angus
 
R

Richard

[Please do not mail me a copy of your followup]

Sam <[email protected]> spake the secret code
In your case, I would use a superclass and two subclasses:

Me too.

Discriminated unions are a C mechanism that people often use to emulate
a class hierarchy. It feels like that's what you're doing here.

I consider the use of unions in C++ a "code smell". Not necessarily
wrong or a bad idea, but usually a sign that you should consider
something else. Ask yourself "How would I do this in an object
oriented language that didn't support unions?" and you usually come up
with a better design.
 
M

Martin Eisenberg

Angus said:
I am modelling a telephony item, called a connection id, which
is made up of two components. A thing called a Call id and a
device id. Both the Call ID and the Device ID could be either a
string or a integer.

My initial design used a union to store the data (a union was
used for performance/code size reasons over templates).
What I would like to do is somehow hide the union and allow
users to set and get using either a std::string or an int. I
have other places where a union with other types are required
and using class objects would be more convenient.

Just like implementation details should not leak to the user, try not
to carry interface conveniences through the implementation. In the
present case, pick a standard internal representation for IDs
(integer or string, whichever is most suitable to the class's work)
and convert to that "normal form" whatever the user passes in. You
might want to centralize the knowledge of how to do the conversion in
a facility separate from the present class.


Martin
 
J

James Kanze

Sam <[email protected]> spake the secret code
<[email protected]> thusly:
Discriminated unions are a C mechanism that people often use
to emulate a class hierarchy. It feels like that's what
you're doing here.

I'm not sure I agree. There are cases when discriminate unions
are really more appropriate, and I this may be one.

First, each id type should be a class in itself. He shouldn't
be writing "union" and "DataType" in the client class, but
rather design an Id class which manages this in itself. Within
the Id class (which should almost certainly have value
semantics), both solutions are possible, but the class hierarchy
more or less means using something like the letter/envelop
idiom, with significant runtime and memory use overhead. And
the actual class probably needs to know about the actual
implementation classes in order to implement things like
operator==. (If you never compare id's, what's the point in
them.)

The discriminate union is a bit trickier to write (although it's
actually less code), but of course, he can get an already
implemented version from Boost (boost::variant). And if for
some reason, he can't use Boost, the idiom is worth learning.
 

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,575
Members
45,053
Latest member
billing-software

Latest Threads

Top