我一直使用结构来打包和接收数据包,我会通过将它们转换为从主数据包类继承的类来获得什么吗?是否有另一种“c++ish”的包装方式以及由此带来的任何性能提升?
2 回答
数据建模
通常,您的 C++ 类应考虑它们建模的数据中的冗余。因此,如果数据包共享一些共同的布局,那么您可以创建一个类来模拟该数据及其上的操作。您可能会发现派生添加其他数据成员以反映可能的数据包数据布局层次结构的类很方便,但有时让不相关的类反映数据包各部分的不同布局可能同样方便(特别是如果长度或顺序的部分消息可能会有所不同)。
为了给出一个符合您想法的最简单案例的更清晰示例 - 如果您有一个标准数据包标头,其中包含一个记录 ID、以字节为单位的记录大小和序列 ID,您可以合理地将这些字段放入一个类中,并公开派生一个每个不同记录 id 的类。基类可能具有成员函数来读取这些值,同时从网络字节顺序转换为本地字节顺序,检查序列 ID 根据需要递增等 - 派生类及其用户都可以访问所有这些值。
运行时多态性
不过,您应该警惕虚拟成员 - 在几乎所有实现中,它们都会在您的对象中引入虚拟调度指针,这可能会阻止它们镜像网络数据包中的数据布局。如果有理由需要运行时多态性(并且很容易,尤其是在读取数据包时),您可能会发现拥有与非多态数据布局的层次结构具有 1:1 对应关系的类的多态层次结构很有用类,并且只包含一个指向内存中数据位置的指针。
表现
使用带有布局的类或结构故意镜像您的网络数据包,可能会让您就地并且非常方便地操作该内存,相信编译器会创建有效的代码来执行此操作。编译器通常很擅长这一点。
该访问的效率(速度)应该完全不受用于对数据建模的类层次结构的影响。涉及的数据偏移和对非虚拟函数的调用都将在编译时解决。
如果您引入虚函数,您可能会看到性能下降,因为它们可以防止内联并需要额外的指针间接,但您应该通过考虑如何在特定于布局的操作之间切换以及您需要的频率来将其放在上下文中支持(例如,switch (record_id)
到处使用if (record_id == X)
,或显式函数指针)。
它非常通用,并且可能有各种解决方案。这与序列化主题有关,您所说的是一个简单的序列化模型,其中数据包包含可以直接加载到内存中的结构,反之亦然。我认为 C 和 C++ 在这种情况下很棒,因为它们允许您直接编写类似 struct 的东西来流式传输并轻松读取它。在其他语言中,您可以实现字节对齐,或者您应该序列化对象以便能够将它们写入流。
在某些情况下,您需要读取 XML、SOAP 等字符串流。在某些应用程序中,您应该使用结构。在某些情况下,您需要将对象序列化为流。这取决于。但我认为使用结构和指针比使用对象序列化更先进。
在您的情况下,我认为每个实体都有 2 个结构。沿线或文件移动的结构和将实体实例保存在内存中的类。如果您对对象使用二进制序列化,则可以只使用一个类来发送、接收和保存实例。