0

I'm porting a networking api I made in java/as3 to c++. I'm quite new to c++ so I'm not that familiar with all the tools that are available.

I have a class called Packet. In my java/as3 class that packet has 2 hashmaps, one for classToId and one for idToClass.

Then I register a derived packet with an id and its class object.

When a packet is received I get its packet ID and then create a new packet with that ID.

In as3 code I then use:

    public static function getNewPacket(id:int):Packet
    {
        try
        {
            var clazz:Class = getClassById[id];
            return (clazz == null ? null : Packet(new clazz()));
        }
        catch (e:Error)
        {
            trace("Skipping packet with id " + id + ": " + e.message);
        }
        return null;
    }

As you can see, reflection is used to call the constructor. In c++ however, I have no idea how I could create this. I can't use a static list of packets because this is a API class.(So this class will be extended in an application using this API)

Duckdoom5
  • 634
  • 6
  • 23
  • Bottom line -- There is no `reflection` in C++. You need to think "outside the Java box" to come up with a solution. – PaulMcKenzie Feb 07 '15 at 23:58
  • That's why I ask on SO, I don't know the tools available to replace reflection. – Duckdoom5 Feb 08 '15 at 00:00
  • What constraints are there on the `Class`es that can be stored in the `getClassById` map? Could they be any class with a no-arg constructor, or are they required to be subclasses of some base class--and is it a base class that's defined in your app, or something else? Or is there a short list of acceptable classes? – ajb Feb 08 '15 at 00:01
  • There is no *tool*. You have to choose a `design pattern` or set of design patterns to accomplish your goal. This isn't a C++ issue, it is an issue of program design and how to accomplish it. http://stackoverflow.com/questions/41453/how-can-i-add-reflection-to-a-c-application – PaulMcKenzie Feb 08 '15 at 00:05

1 Answers1

2

The typical solution is to have a factory function, which connects the ID to the actual class. Say we have a set of classes to deal with shapes:

class Shape { ... };
class Square : public Shape { ... } ;
class Triangle  : public Shape { ... };

enum ShapeID { SquareID, TriangleID, ... }

Shape *shapeFactory(ShapeID id)
{
   switch(id) 
   {
      case SquareID:   return new Square;
      case TriangleID: return new Triangle;
       ...
   };
   return NULL;
}

An alternative, if you don't really know what class you want "until later" is to provide a function that creates the correct ID.

So if you want to be able to EXTEND your shape system with user-defined shapes, you could do something like this:

typedef Shape* (*shapeCreatorFunc)();
... 

Shape* createStar()
{
   return new Star;
}

...
typedef std::map<ID, ShapeCreatorFunc> ShapeMap;
ShapeMap map;
...
map[SquareID] = createSquare;
map[TriangleID] = createTriangle;
map[StarID] = createStar;
....
ShapeMap::iterator it = map.find(id);
if (it != map.end())
{
   Shape *s = it.second();
}

This still relies on the Shape being a common base-class. If that isn't true, I'm not sure how easy it is to solve this in a way that is easy to understand/explain, etc.

Mats Petersson
  • 119,687
  • 13
  • 121
  • 204