从std:string派生以添加typedefs和enum

Derive from std:string to add typedefs and enums

本文关键字:添加 typedefs enum 派生 std string      更新时间:2023-10-16

对于在客户端和服务器之间交换的UDP包,我希望支持两种字符串字段:

名为cstring的以null结尾的c字符串
  • 前一个uint8_t大小字段名为vstring的字符串
  • 为了对包的布局进行自我文档化,我想使用简单的结构声明:

    struct ABC {
    vstring a;
    cstring b;
    }
    

    并在反序列化函数中调用重载函数get(char*, vstring& v)get(char*, cstring&),如下所示:

    void deserialize(const char* bytes, ABC& msg) {
    get(msg.a);
    get(msg.b);
    }
    void serialize(char* bytes, const ABC& msg) {
    put(msg.a);
    put(msg.b);
    }
    

    然而,对于用户来说,理想情况下vstringcstring的行为应该与正常的std::string一样。

    我的第一个想法是简单地将std::string作为vstringcstring的公共基础,这样这两个类在过载解决过程中可以不区分,但对用户来说行为相同。但由于不鼓励从std::string派生,我不确定该怎么办。

    std::string派生的危险在于析构函数不是虚拟的,所以有人可能会这样做:

    std::string* p = new vstring;
    delete p;
    

    你会有不明确的行为。如果你认为这样的代码不可能在你的环境/系统中编写,那就把自己打掉,从std::string派生出来。

    指导方针:

    • 如果vstringcstring类只在非常有限的受控环境中使用,最好是由一个或少数开发人员使用,您可以与他们沟通预期的使用情况并监控实际的使用情况,或者很明显动态分配和多态性不会被滥用来处理它们,这一切都很好。

    • 另一个极端是,如果它们在你的接口中,指向数量不详的不受控制的代码,甚至不可能通知所有潜在的客户端开发人员这个问题,这是不好的,在这种情况下,你应该不喜欢从没有虚拟析构函数的类型派生。


    也就是说,你真的需要在类型中编码串行化风格吗?无论如何,他们都必须编写串行化和去串行化例程,列出要串行化的字段,并且他们还可以在其中指定格式(NUL终止与长度前缀或其他任何格式)。

    从思想上讲,序列化的方式不应该影响数据的类型,所以我最好这样做:

    void serializeNullTerminated(char* bytes, const std::string& msg);
    void deserializeNullTerminated(const char* bytes, std::string& msg);
    void serializeWithSize(char* bytes, const std::string& msg);
    void deserializeWithSize(const char* bytes, std::string& msg);
    

    或者向函数传递一个附加参数:

    void serialize(SerializationType st, char* bytes, const std::string& msg);
    void deserialize(SerializationType st, const char* bytes, std::string& msg);
    

    或者你可以让它们成为模板:

    template<SerializationType st>
    void serialize(char* bytes, const std::string& msg);
    template<SerializationType st>
    void deserialize(const char* bytes, std::string& msg);
    

    关键是,用户不必处理不同类型的字符串,在他们的代码中,他们只需要选择序列化/反序列化的方式。

    您必须将计算与消息解耦。因此,在您的程序中,您使用std::string,当您需要发送/接收字符串时,您会传递符合您的协议的消息。

    因此,你的库/应用程序/任何东西的唯一公共接口应该是这样的:

    int send_message(std::string const &s, int mode, ... destination ... etc);
    int receive_message(std::string &s, int mode, ... source ... etc);
    

    (对于schar *c可能过载(空终止))。

    其中模式是标志CCD_ 20或CCD_。

    内部发送/接收:

    • 一个以null结尾的字符向量或
    • 字符的大小,然后是矢量

    您甚至不需要为cstringvstring创建类。