C ++调用不同的类构造函数,避免切换

时间:2014-10-30 12:44:25

标签: c++ constructor switch-statement

我正在我的程序中捕获一个char*数组的网络数据包。数组的第一个字节表示我收到的数据包的类型,对于每种类型,我希望我的通用Packet基类的单独子类传递给字节数组以及它将被解释的位置。

我想避免使用switch语句,其中将评估数据包的第一个字节并调用相应的构造函数。首先,因为在OOP中你应该避免使用switch子句,其次是因为每次添加数据包类时我都不想在switch语句中添加单独的case。

我查看了工厂方法模式,但我不确定在这种情况下这对我有什么帮助,或者它是否能解决我的问题。

基本上我想避免的是在10个不同的地方编辑我的代码只是为了添加一个数据包类。

4 个答案:

答案 0 :(得分:5)

  

"我想避免使用switch语句......"

在某些时候,无论您是在工厂还是其他地方进行此操作,您都需要区分此字节。

避免switch的一种方法是创建create_class函数的映射,并根据映射键(区分字节值)查找并调用它们。

此解决方案具有以下优势:您可以轻松添加更多密钥和create_class功能,而无需更改基本工厂代码。

答案 1 :(得分:3)

如果数据包类型总是正好是一个字节,那么您可以创建简单的查找表,如下所示:

struct Packet { virtual ~Packet() {} /* ... */ };   // and abstract

std::map<char, std::unique_ptr<Packet>(*)(char const *, std::size_t)> factory;
std::map<char, std::size_t> packet_size;

使用示例:

void handle_input(char const * buf, std::size_t available_size)
{
    if (available_size == 0) { return; }                   // no data

    if (packet_size[buf[0]] > available_size) { return }   // not enough data

    auto p = factory[buf[0]](buf, available_size);         // create packet

    // process p
    // reduce available size by packet_size[buf[0]]
}

<强>实施

struct Type05Packet : Packet
{
    static std::unique_ptr<Packet> make(char const * buf, std::size_t len)
    {
        return std::make_unique<Type05Packet>(buf, len);
    }

private:
   Type05Packet(char const * buf, std::size_t len) { /* populate */ }
};

您必须添加工厂数据(例如在main()中):

factory[5] = &Type05Packet::make;   // creation function for packet '5'
packet_size[5] = 20;                // packet '5' is 20 bytes long

注意:您应该改进几个细节。

  • 数据包创建函数应首先尝试解析数据,如果数据有效则只调用构造函数,否则应返回错误条件(例如nullptr)。
  • 可以在某种自注册全局构造函数中填充工厂和大小映射。为了保持一致,它们也许也可以组合成一个单对的值映射。
  • 地图查找应使用find(buf[0])来满足无法识别的数据包类型。
  • 示例用法可能不太现实。您应该处于某种情况下,您可以根据自己的判断从缓冲区中弹出数据;关键是你只有在有足够的数据形成整个数据包时才这样做。

答案 2 :(得分:1)

是的工厂模式会封装对象创建,你只需要传递它想要创建的对象类型(通过字符串/枚举等)。工厂模式优于普通switch语句的一个主要优点是它本地化对象创建在一个地方。

答案 3 :(得分:0)

考虑使用跳转表。分配一个函数指针数组,由你可以键入消息类型的东西索引,然后在消息处理程序索引该数组并调用所需的函数。