具有不同成员的C ++结构 - 在运行时决定

时间:2011-06-06 17:01:44

标签: c++ class sockets inheritance struct

我有以下情况。下面附有伪代码。我有一个类A,它有一个D或E类型的对象c,这个变化(实际上是随机决定的)。它使用b作为与远程计算机通信的消息。

  1. 那么,我应该如何让struct B拥有不同的变量(在这种情况下为float或double)?
  2. 此外,当我打开一个套接字并传输一个对象时,该对象现在将具有不同的大小。远程计算机不知道对象的大小是否与sizeof(int)+ sizeof(float)或sizeof(int)+ sizeof(double)相对应。我需要大小作为接收数据包的参数,那么我该如何解决这个问题呢?
  3. 代码:

    class C 
    {
      ...
    };
    
    class D: public C
    {
      ...
    };
    
    class E: public C
    {
      ...
    };
    
    struct B
    {
      int a;
      // If A->c is of type D
      float b;
      // If A->c is of type E
      double b;
    };
    
    class A
    {
      B b;
      C *c;
      A()
      {
        c = (C*) new D;
        //c = (C*) new E;
      }
      ...
      ...
      void transmit()
      {
        //b has some attributes depending on whether c is of type D or E
        //Open a socket and send packets via UDP
        //The remote host receives the packets
      }
    };
    

    我希望这能解释我的问题。如果不清楚或含糊不清,请告诉我。我会提供更多细节和解释。提前谢谢。

5 个答案:

答案 0 :(得分:2)

使用 factory pattern 在运行时创建对象。

或者,使用模板:

template <class T>
class A {
   T a;
}


A<int> a = new A<int>();
A<double> b = new A<double>();

第二部分很容易。
在你的发送 - 接收协议中,在sizeof(int)的开头保留4个字节......然后用sizeof(a)填充它

答案 1 :(得分:1)

由于D和E都来自C,因此您的实现看起来是正确的:

c = (C*) new D;

虽然我会删除C-Cast(不需要,如果你需要强制转换,你应该使用C ++变体)。

c = new D;

您如何传输数据取决于。但通常您需要在信息的前面加上类型信息的前缀,以便目的地了解如何解码后续流。

send(a->a);
send("1") if a->c is D
send("2") if a->c is E
send(<Conditional Part>);

作为旁注。查找智能指针。在你的类中使用原始指针是一个坏主意(而不是很好的C ++)。

答案 2 :(得分:1)

使用普通C ++和原始套接字是非常繁忙的,很多人最终通过套接字传递结构而不考虑其他问题因此而上升..

  1. 您需要了解big-endian和host-endian转换
  2. 并非所有编译器都按原样处理结构..您经常需要使用#pragma pack来强制处理结构的大小。有些编译器不支持此功能。
  3. 如果您不担心性能,我建议将数据作为XML / ini内容发送,这很容易解析.INI读者可以方便地将参数读取为float或double ..

    如果您仍然喜欢二进制内容,我建议您学习ASN.1符号,但至少需要2周时间才能完成项目练习,然后您将结束使用现有协议或使用自定义协议。< / p>

    因此,您的问题无法直接解决。您可以要求您的类C或D通过套接字发送序列化数据,而不是发送内存的结构副本,并将对象的类型作为第一个字节,下一个2/4字节的数据长度,实际数据到然后继续..然后实现一个读取第一个字节的读取器类,然后决定对象的类型,然后将调用委托给相应的类来读取其余的数据。

答案 3 :(得分:1)

首先,您的类层次结构看起来很可疑。根据您显示的内容,BC之间没有任何关系,除了存在第三种类型A,其中包含B个对象和{ {1}}指针。然而,C内的变量类型应该取决于B对象内的指针指向C的哪个子类?

这似乎是不必要的耦合。为什么不将A中的B字段合并到C的各个子类中?

假设你已经修复了你的类层次结构,你就会遇到一个相对直接的问题,即想要在套接字上发送两种不同类型的消息(不同大小)中的一种。这是一个解决方案:

enum message_type {type1, type2};

class message_type1
{
    ...
};

class message_type2
{
    ...
};

// when sending message (pseudocode)
write message_type variable
write message_type1 object OR message_type2 object

// when reading message (pseudocode)
read message_type variable
if type1
    read message_type1 object
else
    read message_type2 object

当然,message_type1message_type2可以通过作为相同基类的子类或相同模板等的实例来关联,以避免重复,如果这两种消息类型有一些共同点

编辑:您在评论中提到其他答案,您无法将邮件拆分为不同的数据包。你能澄清一下这意味着什么吗? “数据包”不是一个精确的术语:TCP具有,UDP和IP具有数据报,以太网具有。这些都与您在套接字上调用send()的次数有关(即两次调用send() 必然意味着发送两个TCP段;相反,拨打send()只需 确保您的数据会在一个网段中传输。

答案 4 :(得分:0)

Union可以用来解决问题。

struct B
{
  int a;
  bool d; //d = 0 for D and 1 for E
  union
  {
    float b;
    double c;
  }
};