Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. C++ class hierarchy design problem

C++ class hierarchy design problem

Scheduled Pinned Locked Moved C / C++ / MFC
helpquestionc++designhardware
10 Posts 5 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    kylur
    wrote on last edited by
    #1

    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

    J B C C 4 Replies Last reply
    0
    • K kylur

      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

      J Offline
      J Offline
      Jonathan Davies
      wrote on last edited by
      #2

      How about Template specialization?

      template<> class IPipe<short>
      {
      ...
      return v._i16;
      ...
      }
      template class IPipe<long>
      {
      ...
      return v._i32;
      ....
      }

      K 1 Reply Last reply
      0
      • K kylur

        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

        B Offline
        B Offline
        Bernodus Kristinsson
        wrote on last edited by
        #3

        template<typename T> T
        get_the_value(gen_scalar const& gs) const;// primary template no need for definition

        template<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

        K 1 Reply Last reply
        0
        • K kylur

          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

          C Offline
          C Offline
          cmk
          wrote on last edited by
          #4

          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

          K 1 Reply Last reply
          0
          • K kylur

            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

            C Offline
            C Offline
            code_slashxx
            wrote on last edited by
            #5

            mark.

            K 1 Reply Last reply
            0
            • J Jonathan Davies

              How about Template specialization?

              template<> class IPipe<short>
              {
              ...
              return v._i16;
              ...
              }
              template class IPipe<long>
              {
              ...
              return v._i32;
              ....
              }

              K Offline
              K Offline
              kylur
              wrote on last edited by
              #6

              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.

              1 Reply Last reply
              0
              • C cmk

                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

                K Offline
                K Offline
                kylur
                wrote on last edited by
                #7

                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.

                C 1 Reply Last reply
                0
                • C code_slashxx

                  mark.

                  K Offline
                  K Offline
                  kylur
                  wrote on last edited by
                  #8

                  Huh?

                  1 Reply Last reply
                  0
                  • B Bernodus Kristinsson

                    template<typename T> T
                    get_the_value(gen_scalar const& gs) const;// primary template no need for definition

                    template<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

                    K Offline
                    K Offline
                    kylur
                    wrote on last edited by
                    #9

                    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. :)

                    1 Reply Last reply
                    0
                    • K 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.

                      C Offline
                      C Offline
                      cmk
                      wrote on last edited by
                      #10

                      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

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups