Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;调用不同的类构造函数,避免切换_C++_Constructor_Switch Statement - Fatal编程技术网

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

C++ C++;调用不同的类构造函数,避免切换,c++,constructor,switch-statement,C++,Constructor,Switch Statement,我正在程序中捕获一个网络数据包作为char*数组。数组的第一个字节表示我收到的数据包的类型,对于每种类型,我希望有一个通用数据包基类的单独子类,我将字节数组传递到该基类,并在其中解释它 我希望避免使用switch语句来计算数据包的第一个字节并调用相应的构造函数。首先是因为在OOP中,您应该避免switch子句,其次是因为我不想在每次添加packet类时向switch语句添加单独的大小写 我研究了工厂方法模式,但我不确定这在这种情况下对我有什么帮助,或者它是否能解决我的问题 基本上,我想要避免的是

我正在程序中捕获一个网络数据包作为
char*
数组。数组的第一个字节表示我收到的数据包的类型,对于每种类型,我希望有一个通用
数据包
基类的单独子类,我将字节数组传递到该基类,并在其中解释它

我希望避免使用switch语句来计算数据包的第一个字节并调用相应的构造函数。首先是因为在OOP中,您应该避免switch子句,其次是因为我不想在每次添加packet类时向switch语句添加单独的大小写

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

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

“我希望避免使用switch语句…”

在某个时候,您需要区分这个字节,无论您是在工厂还是在其他地方这样做

避免切换的一种方法是创建
create_class
函数的映射,并根据映射键(区分字节值)查找和调用这些函数


此解决方案的优点是,您可以轻松添加更多的键和创建类函数,而无需更改基本的工厂代码。

是的,工厂模式将封装对象创建,您只需将要创建的对象类型传递给它(通过字符串/枚举等)factory模式与普通switch语句相比的一个主要优点是,它将对象创建定位在一个位置。

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

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 */ }
};
注意:有几个细节需要改进

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

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

工厂模式不会避免切换,而是封装切换,它只会发生一次!您在运行时确定类型,因此必须使用运行时构造,如if-else梯形图的开关。不要太执着于“在OOP中,你应该避免使用switch子句”这样的短语。我认为最优雅的解决方案是有一个函数指针的映射,指向工厂函数。每个子类型一个,键是从char数组读取的字节值。
factory[5] = &Type05Packet::make;   // creation function for packet '5'
packet_size[5] = 20;                // packet '5' is 20 bytes long