我正在移植我在java / as3到c ++中创建的网络api。我对c ++很陌生,所以我对所有可用的工具都不熟悉。
我有一个叫做Packet的课程。在我的java / as3类中,数据包有2个哈希映射,一个用于classToId,另一个用于idToClass。
然后我注册一个带有id及其类对象的派生数据包。
收到数据包后,我会获取其数据包ID,然后创建一个包含该ID的新数据包。
在as3代码中,我然后使用:
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;
}
如您所见,反射用于调用构造函数。 但是在c ++中,我不知道如何创建它。 我不能使用静态的数据包列表,因为这是一个API类。(因此这个类将在使用此API的应用程序中进行扩展)
答案 0 :(得分:2)
典型的解决方案是拥有一个工厂功能,它将ID连接到实际的类。假设我们有一组类来处理形状:
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;
}
另一种选择,如果你真的不知道你想要什么类,“直到以后”是提供一个创建正确ID的函数。
因此,如果您希望能够使用用户定义的形状扩展您的形状系统,您可以执行以下操作:
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();
}
这仍然依赖于Shape
是一个共同的基类。如果不是这样,我不确定以易于理解/解释等方式解决这个问题是多么容易。