dynamic type -> how do I do this?

Dec 3, 2008 at 12:04pm
I am writing a program that processes data-streams. The streams differ a bit in their data-layout, e.g.:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
typedef struct
{
  u_char ChannelIdHigh            :8;
  u_char ChannelIdLow             :8;
  u_char                          :8;
  u_char                          :8;
  u_char                          :8;
  u_char DayHigh                  :8;
  u_char DayLow                   :8;
} TitleSKY;

typedef struct
{
  u_char ThemeId                  :8;
  u_char ChannelIdHigh            :8;
  u_char ChannelIdLow             :8;
  u_char Day                      :8;
  u_char DurationHigh             :8;
  u_char DurationLow              :8;
} TitleMHW1;

What I would like to do is like this:

if (Format = 1) //use TitleSKY
   TitleSKY *Title = (TitleSKY *) Data;
else
   TitleMHW1 *Title = (TitleMHW1 *) Data;

int ChannelId = (Title->ChannelIdHigh << 8) || (Title->ChannelIdLow);
...etc.


Of course this does not work, since the declarations in the if-else are not valid in the rest of the code. I end up writing two separate routines which are doing exactly the same, except for the data-type.

How would a real programmer solve this problem more elegantly?

Thanks!


Last edited on Dec 3, 2008 at 12:06pm
Dec 3, 2008 at 1:31pm
There are two paths you can follow:
1. Merge the two types and have a type value that will tell you of which type is any given instance.
2. Have both classes derive from the same class. Then you can take advantage of polymorphism:
1
2
3
4
5
BaseTitle *Title;
if (Format = 1) //use TitleSKY
   Title=new TitleSKY(Data);
else
   Title=new TitleMHW1(Data);
Dec 3, 2008 at 3:24pm
Thanks Helios,

I'm not sure whether I understand your first option correctly, but your second suggestion is what I was looking for; this seems to be the "clean" way to go.

Thanks a lot for your quick answer!
Dec 4, 2008 at 1:04pm
I am studing the polymorphism solution suggested here, but I can't think of how polymorphism can be used for dynamic typing.

I cannot use inheritance, since the specific datatypes reside in the child-objects TitleSky and TitleMHW1 , and obviously only children can inherit from their parents and not the other way around.

So I think I must use the override mechanism, to override some dummy-datatype in the BaseTitle class, but I understand that you can only override methods and not variables (am I correct in that?).

So then I am forced to use an overriding method, but with a method I MUST specify compile-time data-types, so not usable for overriding a data-type run-time.

This is what I have right now:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class BaseTitle
{
public:
  virtual int SetFormat (const u_char * Data, int Length)//TODO do I need this dummy?
  {
   sTitle *Title = (sTitle *) Data;
   return  BaseTitle::ReadTitle(Data, Length,Title);
  }


};

class TitleMHW1:public BaseTitle
{
public:
   virtual int SetFormat (const u_char * Data, int Length)
  {
   sTitleMHW1 *Title = (sTitleMHW1 *) Data;
   return  BaseTitle::ReadTitle(Data, Length,Title);//damn, now I must specify title type again, 
//and all these classes where meant to prevent this
  }
};


Another possibility would be to write a separate method for every child, but then I get massive code replication because only the data-structures differ slightly, the rest is all the same...


Am I making a mistake here, or is the solution proposed not right?

Thanks in advance!
Last edited on Dec 4, 2008 at 1:10pm
Dec 4, 2008 at 2:23pm
If your structs are modeling a data format that you do not control then there is nothing you can do. On the other hand, if you can reorder the data members, then move the common data members to a base class. This is what helios was suggesting. And remove the :8 unless you are expecting to run on a machine whose byte size is greater than 8 bits.

Dec 4, 2008 at 2:30pm
Hi Jsmith,

The data-order is defined by the stream, which is sent by satellite; I'm afraid I cannot change that order... too bad that I can't restructure my program better, now I just stick to having separate routines per data-type :-( .

Thanks!
Dec 4, 2008 at 3:38pm
Would adding a base class with templated methods to be called from derived classes help any? It still won't remove the derived code, but it may cut it back if you can generalize the methods (like the example SetFormat method).
Dec 4, 2008 at 3:45pm
I don't think that will help a lot; the derived code would look like this:

1
2
3
4
5
6
7
8
9
10
11
12
sTitleMHW1 *Title = (sTitleMHW1 *) Data;

T->ChannelId = Title -> (ChannelIdHigh << 8 || ChannelIdLow);
T->ThemeId = Title ->ThemeId;
....etc....

and other derivation:

sTitleSKY *Title = (sTitleSKY *) Data;
T->ChannelId = Title -> (ChannelIdHigh << 8 || ChannelIdLow);
T->ThemeId = Title ->ThemeId;
....etc....


So all derived code would be exactly the same, because the format translation is done by changing the datatype.
But since the derived code is dependent on the data-type, you cannot move it to the generalised class (if I understand correctly). That is exactly the problem with the SetFormat example shown....


Last edited on Dec 4, 2008 at 3:46pm
Topic archived. No new replies allowed.