C++ class hierarchy design problem
-
Fellow coders, RE: a C++ design problem. I am attempting to construct a C++ class hierarchy on top of a C legacy system. The result will be then placed into an embedded controller. The controller communicates with a Windows program via a series of 'software pipes' to a supplied DLL and then calls in the Windows program to fetch information from the DLL. The data in a given pipe will be of a specific type. In order to generalize this process the third party library uses the following header:
typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef union gen\_scalar { double \_double; \_\_int64 \_i64; float \_float; long \_i32; short \_i16; DWORD \_long; WORD \_word; BYTE \_byte; } GENERIC\_SCALAR;
And then, for example, reading a long from a pipe would be:
long Get(PIPE\* pipe) { GENERIC\_SCALAR v; pipe\_value\_get(pipe, &v); Return v.\_i32; };
So, the hierarchy starts with a base class:
class Pipe { public: Pipe(PIPE\* pipe) : pipe\_(pipe) {}; virtual ~Pipe() {}; protected: PIPE\* pipe\_; };
where a PIPE* is just a handle to the communication pipe. Then an input class is needed:
class IPipe : public Pipe { public: IPipe(PIPE\* pipe) : Pipe(pipe) { pipe\_open(pipe\_, P\_READ); }; };
There would also be a corresponding output class OPipe. And now the part I need help with! Suppose I know a pipe will contain a series of 'shorts'. Then I could create:
class ShortIPipe : public IPipe { public: ShortIPipe(IPIPE\* pipe) : IPipe(pipe) {}; short Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return v.\_i16; }; };
And so on for a long, double, float, etc, pipe(s). However, the only difference between all these classes is the return value, that is, v._i16 or v._i32, etc. I'd prefer to create a single class which can handle them all. Maybe a template class? For example:
template <typename T> class IPipe : public Pipe { public: IPipe(PIPE\* pipe) : Pipe(pipe) { pipe\_open(pipe\_, P\_READ); }; T Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return v.\_???;// depends on T }; };
Used like:
IPipe<short> spipe(...); short s = spipe.Get();
And so, (finally) the question is how, within the Get() member, do I define the return value? No
-
Fellow coders, RE: a C++ design problem. I am attempting to construct a C++ class hierarchy on top of a C legacy system. The result will be then placed into an embedded controller. The controller communicates with a Windows program via a series of 'software pipes' to a supplied DLL and then calls in the Windows program to fetch information from the DLL. The data in a given pipe will be of a specific type. In order to generalize this process the third party library uses the following header:
typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef union gen\_scalar { double \_double; \_\_int64 \_i64; float \_float; long \_i32; short \_i16; DWORD \_long; WORD \_word; BYTE \_byte; } GENERIC\_SCALAR;
And then, for example, reading a long from a pipe would be:
long Get(PIPE\* pipe) { GENERIC\_SCALAR v; pipe\_value\_get(pipe, &v); Return v.\_i32; };
So, the hierarchy starts with a base class:
class Pipe { public: Pipe(PIPE\* pipe) : pipe\_(pipe) {}; virtual ~Pipe() {}; protected: PIPE\* pipe\_; };
where a PIPE* is just a handle to the communication pipe. Then an input class is needed:
class IPipe : public Pipe { public: IPipe(PIPE\* pipe) : Pipe(pipe) { pipe\_open(pipe\_, P\_READ); }; };
There would also be a corresponding output class OPipe. And now the part I need help with! Suppose I know a pipe will contain a series of 'shorts'. Then I could create:
class ShortIPipe : public IPipe { public: ShortIPipe(IPIPE\* pipe) : IPipe(pipe) {}; short Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return v.\_i16; }; };
And so on for a long, double, float, etc, pipe(s). However, the only difference between all these classes is the return value, that is, v._i16 or v._i32, etc. I'd prefer to create a single class which can handle them all. Maybe a template class? For example:
template <typename T> class IPipe : public Pipe { public: IPipe(PIPE\* pipe) : Pipe(pipe) { pipe\_open(pipe\_, P\_READ); }; T Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return v.\_???;// depends on T }; };
Used like:
IPipe<short> spipe(...); short s = spipe.Get();
And so, (finally) the question is how, within the Get() member, do I define the return value? No
How about Template specialization?
template<> class IPipe<short>
{
...
return v._i16;
...
}
template class IPipe<long>
{
...
return v._i32;
....
} -
Fellow coders, RE: a C++ design problem. I am attempting to construct a C++ class hierarchy on top of a C legacy system. The result will be then placed into an embedded controller. The controller communicates with a Windows program via a series of 'software pipes' to a supplied DLL and then calls in the Windows program to fetch information from the DLL. The data in a given pipe will be of a specific type. In order to generalize this process the third party library uses the following header:
typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef union gen\_scalar { double \_double; \_\_int64 \_i64; float \_float; long \_i32; short \_i16; DWORD \_long; WORD \_word; BYTE \_byte; } GENERIC\_SCALAR;
And then, for example, reading a long from a pipe would be:
long Get(PIPE\* pipe) { GENERIC\_SCALAR v; pipe\_value\_get(pipe, &v); Return v.\_i32; };
So, the hierarchy starts with a base class:
class Pipe { public: Pipe(PIPE\* pipe) : pipe\_(pipe) {}; virtual ~Pipe() {}; protected: PIPE\* pipe\_; };
where a PIPE* is just a handle to the communication pipe. Then an input class is needed:
class IPipe : public Pipe { public: IPipe(PIPE\* pipe) : Pipe(pipe) { pipe\_open(pipe\_, P\_READ); }; };
There would also be a corresponding output class OPipe. And now the part I need help with! Suppose I know a pipe will contain a series of 'shorts'. Then I could create:
class ShortIPipe : public IPipe { public: ShortIPipe(IPIPE\* pipe) : IPipe(pipe) {}; short Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return v.\_i16; }; };
And so on for a long, double, float, etc, pipe(s). However, the only difference between all these classes is the return value, that is, v._i16 or v._i32, etc. I'd prefer to create a single class which can handle them all. Maybe a template class? For example:
template <typename T> class IPipe : public Pipe { public: IPipe(PIPE\* pipe) : Pipe(pipe) { pipe\_open(pipe\_, P\_READ); }; T Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return v.\_???;// depends on T }; };
Used like:
IPipe<short> spipe(...); short s = spipe.Get();
And so, (finally) the question is how, within the Get() member, do I define the return value? No
template<typename T> T
get_the_value(gen_scalar const& gs) const;// primary template no need for definitiontemplate<double> inline double
get_the_value(gen_scalar const& gs) const { return gs._double; }template<short> short inline
get_the_value(gen_scalar const& gs) const { return gs._i16; }//... and so on for all types in the union (never remember the placement of inline)
template<typename T>
class IPipe : public Pipe
{
public:
IPipe(PIPE* pipe) : Pipe(pipe) { pipe_open(pipe_, P_READ); };T Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return get\_the\_value<T>(v);// important: <T> };
};
// several small functions instead of same number of classes
-
Fellow coders, RE: a C++ design problem. I am attempting to construct a C++ class hierarchy on top of a C legacy system. The result will be then placed into an embedded controller. The controller communicates with a Windows program via a series of 'software pipes' to a supplied DLL and then calls in the Windows program to fetch information from the DLL. The data in a given pipe will be of a specific type. In order to generalize this process the third party library uses the following header:
typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef union gen\_scalar { double \_double; \_\_int64 \_i64; float \_float; long \_i32; short \_i16; DWORD \_long; WORD \_word; BYTE \_byte; } GENERIC\_SCALAR;
And then, for example, reading a long from a pipe would be:
long Get(PIPE\* pipe) { GENERIC\_SCALAR v; pipe\_value\_get(pipe, &v); Return v.\_i32; };
So, the hierarchy starts with a base class:
class Pipe { public: Pipe(PIPE\* pipe) : pipe\_(pipe) {}; virtual ~Pipe() {}; protected: PIPE\* pipe\_; };
where a PIPE* is just a handle to the communication pipe. Then an input class is needed:
class IPipe : public Pipe { public: IPipe(PIPE\* pipe) : Pipe(pipe) { pipe\_open(pipe\_, P\_READ); }; };
There would also be a corresponding output class OPipe. And now the part I need help with! Suppose I know a pipe will contain a series of 'shorts'. Then I could create:
class ShortIPipe : public IPipe { public: ShortIPipe(IPIPE\* pipe) : IPipe(pipe) {}; short Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return v.\_i16; }; };
And so on for a long, double, float, etc, pipe(s). However, the only difference between all these classes is the return value, that is, v._i16 or v._i32, etc. I'd prefer to create a single class which can handle them all. Maybe a template class? For example:
template <typename T> class IPipe : public Pipe { public: IPipe(PIPE\* pipe) : Pipe(pipe) { pipe\_open(pipe\_, P\_READ); }; T Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return v.\_???;// depends on T }; };
Used like:
IPipe<short> spipe(...); short s = spipe.Get();
And so, (finally) the question is how, within the Get() member, do I define the return value? No
Did you try: return (T&)v;
...cmk The idea that I can be presented with a problem, set out to logically solve it with the tools at hand, and wind up with a program that could not be legally used because someone else followed the same logical steps some years ago and filed for a patent on it is horrifying. - John Carmack
-
Fellow coders, RE: a C++ design problem. I am attempting to construct a C++ class hierarchy on top of a C legacy system. The result will be then placed into an embedded controller. The controller communicates with a Windows program via a series of 'software pipes' to a supplied DLL and then calls in the Windows program to fetch information from the DLL. The data in a given pipe will be of a specific type. In order to generalize this process the third party library uses the following header:
typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef union gen\_scalar { double \_double; \_\_int64 \_i64; float \_float; long \_i32; short \_i16; DWORD \_long; WORD \_word; BYTE \_byte; } GENERIC\_SCALAR;
And then, for example, reading a long from a pipe would be:
long Get(PIPE\* pipe) { GENERIC\_SCALAR v; pipe\_value\_get(pipe, &v); Return v.\_i32; };
So, the hierarchy starts with a base class:
class Pipe { public: Pipe(PIPE\* pipe) : pipe\_(pipe) {}; virtual ~Pipe() {}; protected: PIPE\* pipe\_; };
where a PIPE* is just a handle to the communication pipe. Then an input class is needed:
class IPipe : public Pipe { public: IPipe(PIPE\* pipe) : Pipe(pipe) { pipe\_open(pipe\_, P\_READ); }; };
There would also be a corresponding output class OPipe. And now the part I need help with! Suppose I know a pipe will contain a series of 'shorts'. Then I could create:
class ShortIPipe : public IPipe { public: ShortIPipe(IPIPE\* pipe) : IPipe(pipe) {}; short Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return v.\_i16; }; };
And so on for a long, double, float, etc, pipe(s). However, the only difference between all these classes is the return value, that is, v._i16 or v._i32, etc. I'd prefer to create a single class which can handle them all. Maybe a template class? For example:
template <typename T> class IPipe : public Pipe { public: IPipe(PIPE\* pipe) : Pipe(pipe) { pipe\_open(pipe\_, P\_READ); }; T Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return v.\_???;// depends on T }; };
Used like:
IPipe<short> spipe(...); short s = spipe.Get();
And so, (finally) the question is how, within the Get() member, do I define the return value? No
mark.
-
How about Template specialization?
template<> class IPipe<short>
{
...
return v._i16;
...
}
template class IPipe<long>
{
...
return v._i32;
....
}Thanks for the reply, Jonathan. Yes, this works - if fact it was my original attempt! I rejected it only because it just looked too wordy - I know, bad reason but I've got a little extra time to do investigations on this project so I thought I'd try a few other ideas. Regards, Kylur.
-
Did you try: return (T&)v;
...cmk The idea that I can be presented with a problem, set out to logically solve it with the tools at hand, and wind up with a program that could not be legally used because someone else followed the same logical steps some years ago and filed for a patent on it is horrifying. - John Carmack
Thanks for the reply, "cmk". And no I had not tried your suggestion. But now I (almost) have (I used return reinterpret_cast(v);) and yes it does work! And I'm not sure if you're a friggin' genius or if I'm just an idiot for not seeing this solution. For some unknown reason however, I'm a little reluctant to use this - "gurus" tend to frown on casts and in this case I'm not really sure what a reinterpret_cast of a union is really doing (although I have to say it does seem to work). I'll really have to think about this some more! Regards, Kylur.
-
mark.
-
template<typename T> T
get_the_value(gen_scalar const& gs) const;// primary template no need for definitiontemplate<double> inline double
get_the_value(gen_scalar const& gs) const { return gs._double; }template<short> short inline
get_the_value(gen_scalar const& gs) const { return gs._i16; }//... and so on for all types in the union (never remember the placement of inline)
template<typename T>
class IPipe : public Pipe
{
public:
IPipe(PIPE* pipe) : Pipe(pipe) { pipe_open(pipe_, P_READ); };T Get() const { GENERIC\_SCALAR v; pipe\_value\_get(pipe\_, &v); return get\_the\_value<T>(v);// important: <T> };
};
// several small functions instead of same number of classes
Thank you for the reply, Berndus. This answer really caught my eye as it 1) took advantage on templates and specialization, 2) the helper functions can all be moved into the IPipe class as private members, 3) is understandable and 4) is short. Looking closer at the get_the_value functions and they start to look very similar to the reinterpret_cast as suggested in another reply - the only difference being explicitly returning the union member. Good job! I think this is the solution I'll use. Regards, Kylur. :)
-
Thanks for the reply, "cmk". And no I had not tried your suggestion. But now I (almost) have (I used return reinterpret_cast(v);) and yes it does work! And I'm not sure if you're a friggin' genius or if I'm just an idiot for not seeing this solution. For some unknown reason however, I'm a little reluctant to use this - "gurus" tend to frown on casts and in this case I'm not really sure what a reinterpret_cast of a union is really doing (although I have to say it does seem to work). I'll really have to think about this some more! Regards, Kylur.
20 yrs of C++, more for C. There is NOTHING wrong with using the (T&) cast.
...cmk The idea that I can be presented with a problem, set out to logically solve it with the tools at hand, and wind up with a program that could not be legally used because someone else followed the same logical steps some years ago and filed for a patent on it is horrifying. - John Carmack