C++->network设计

本文介绍了一种游戏服务器网络层的设计思路,包括使用IO复用模型select、定义协议号及处理逻辑回调函数、设计Receiver类等内容。此外,还讨论了如何通过封装提高代码的复用性和效率。

现行开发的软件中,基本没有啥是不联网的。连一个小小的游戏,也要联网,去下载点广告什么的。那么网络层的是不是可以有很多东西可以重用的呢?


本人之前在一个游戏公司做服务器端开发。有一个网络架构是这样设计的。


网络使用了IO复用模型select。当然,对于现在的服务器,可以使用epoll代替。


一个Opcodes类,类成员都是静态的常量,用于表示与服务器通信的操作码。我们称它们为协议号。对于每一个操作,都会有一个协议号对应。比如客户端登录,客户端发给服务器进验证,使用一个CSLOGIN的常量表示。服务器验证后,将结果返回,可以使用一个SCLOGIN的常量表示。等等。


一个Optable类。这个类使用一std::map来记录每一个协议号的操作。map中的first value是协议号,second value是对应协议的处理逻辑回调函数。这个类应该设计成单例的。在main函数中,进行网络通信之前应该将这个单例中的map设计好,即将所有的协议号和回调函数insert到map中。这里还有一点要求,就是回调函数的声明必须是一样 ,不然map就定义不了。所以,回调函数可以设计成void (*)(unsigned char*)这样结构。因为收到的消息也是字节流。先从流中解析出包的长度,再解析出该长度的消息。当然,为了方便处理,还可以封装多一层函数,这个函数的功能是这样的:我们定义协议的时候,会要求将什么参数传到网络中去,比如将用户名和密码发给服务器,那么就会参数就会是这样string name, string password。这样就可以在回调函数中调用相应的这个函数,而这个函数应该由子类去重写其对应的业务逻辑。那这些业务逻辑应该放在哪里呢?下面讨论。


设计一个Receiver类,让要进行接收消息的端去继承这个类。比如,服务器可以有一个用于监听连接的类,然后这个类的函数监听到一个连接,然后将这个连接new一个新的对象,而这个对象所对应的类应该继承Receiver类,这样就可以去重写上面所说的方法了。


整理一下逻辑(以服务器为例):

  1. 服务器收到包,发给对应的处理对象。
  2. 解析出协议号。
  3. 在optable中根据协议号找出处理函数。
  4. 处理函数调用重写的业务逻辑函数进行处理。

也就是说,这个网络层是有东西可以封装的。如果封闭了服务器(客户端),optable, receiver等类,那么,以后要用这个网络层,只要在opcodes中加入协议号。子类化receiver类,就能进行处理这些逻辑。

以上是网络层的设计思想。也可以看成是一个概要设计。

当然,在实际使用中,已经有了很多网络架构,如ICE,ACE等,可以使用这些架构使项目的速度快很多。但是,自己封装的网络层可以进行自己定制,实现更高效的网络架构。见仁见智吧。

<think> 我们正在解决一个C++编程问题:在AI类的构造函数中,我们试图使用QNetwork类,但编译器报错说QNetwork类没有默认构造函数。这意味着我们在创建AI类的成员对象时,没有提供必要的参数给QNetwork的构造函数。 根据C++的规则,如果一个类没有定义默认构造函数(即无参构造函数),那么当我们尝试以默认方式构造该类的对象时,编译器会报错。在这种情况下,我们需要在包含对象(这里是AI类)的构造函数初始化列表中显式调用QNetwork的有参构造函数。 假设QNetwork类有一个需要参数的构造函数(例如,它可能需要一些配置参数),那么在AI类的构造函数中,我们不能直接写: QNetwork network; // 错误:因为QNetwork没有默认构造函数 而应该在AI的构造函数的初始化列表中显式调用QNetwork的构造函数,并传入所需的参数。 例如,如果QNetwork的构造函数需要一个整数参数(比如层数),那么AI的构造函数应该这样写: AI::AI() : network(3) // 假设3是所需的参数 { // 构造函数体 } 如果QNetwork的构造函数需要多个参数,则同样在初始化列表中提供。 另一种情况是,如果QNetwork类本身确实没有提供任何无参构造函数,而我们又无法修改QNetwork类的源代码(比如它是第三方库),那么我们必须按照它已有的构造函数来传递参数。 因此,解决步骤: 1. 查看QNetwork类的定义,确定它有哪些可用的构造函数,特别是需要哪些参数。 2. 在AI类的构造函数初始化列表中,使用合适的参数来初始化QNetwork成员对象。 如果AI类本身在构造时也需要从外部获取参数,并且这些参数需要传递给QNetwork,那么我们应该修改AI的构造函数,增加对应的参数,然后在初始化列表中使用这些参数来构造QNetwork。 例如: // AI.h class AI { public: AI(int network_layer); // 增加参数 private: QNetwork network; }; // AI.cpp AI::AI(int network_layer) : network(network_layer) { // ... } 这样,在创建AI对象时,就需要传入一个整数参数,这个参数会用于构造QNetwork对象。 如果QNetwork的构造参数在AI类构造时还无法确定,那么可能需要重新设计,比如使用指针和动态分配,然后在构造AI之后通过一个初始化函数来创建QNetwork对象。但这样会使得对象的状态管理复杂化,通常建议在构造时完成初始化。 因此,主要的解决方案就是在AI的构造函数初始化列表中显式调用QNetwork的有参构造函数,并传递所需的参数。 另外,如果QNetwork类不是AI类的成员,而是在构造函数内部作为局部变量创建,那么同样需要以带参数的方式创建,例如: AI::AI() { QNetwork network(参数); // 正确:调用有参构造函数 // ... } 但这里问题描述的是在AI构造函数中使用QNetwork类报错,并且提到“类QNetwork不存在默认构造函数”,所以更可能是作为成员变量而没有正确初始化。 总结:检查AI类的定义,看QNetwork是否是其成员变量。如果是,则在AI构造函数的初始化列表中为QNetwork提供必要的参数。 如果没有在初始化列表中初始化,编译器会尝试使用默认构造函数,但QNetwork没有,因此报错。 因此,请检查AI类的头文件,确认QNetwork成员,然后在实现AI构造函数时使用初始化列表。 </think>要解决在`AI::AI()`构造函数中因`QNetwork`类缺少默认构造函数而报错的问题,关键在于正确初始化成员对象。以下是具体解决方案: ### 解决方法 1. **在初始化列表中显式调用有参构造函数** 修改`AI`类的构造函数,在**初始化列表**中传递`QNetwork`所需的参数: ```cpp // AI.h 头文件 class AI { public: AI(int inputSize, int hiddenSize, int outputSize); // 声明带参数的构造函数 private: QNetwork network; // 成员对象 }; // AI.cpp 实现文件 AI::AI(int inputSize, int hiddenSize, int outputSize) : network(inputSize, hiddenSize, outputSize) // ✅ 关键:在初始化列表构造QNetwork { // 其他初始化代码 } ``` 2. **避免在构造函数体内赋值** 以下写法会触发默认构造(导致报错): ```cpp // ❌ 错误写法:会先尝试调用默认构造函数 AI::AI() { network = QNetwork(10, 20, 5); // 此处实际调用了两次构造函数 } ``` ### 原因分析 - **默认构造函数缺失**:`QNetwork`未定义`QNetwork()`形式的无参构造函数。 - **成员初始化规则**:C++要求所有成员对象在进入构造函数体前完成初始化。若未在初始化列表中指定,编译器会尝试调用默认构造函数,从而引发报错[^4]。 ### 验证场景 假设`QNetwork`类定义为: ```cpp class QNetwork { public: QNetwork(int in, int hid, int out); // 只有带参构造函数 // 无 QNetwork() 默认构造函数 }; ``` 此时必须通过初始化列表传递参数。 ### 其他注意事项 - **参数来源**:若`AI`类自身需要外部参数构造`QNetwork`,应修改`AI`的构造函数签名: ```cpp // 调用示例 AI my_ai(128, 64, 10); // 传递网络结构参数 ``` - **指针方案(备选)**: 若无法修改构造流程,可改用指针延迟初始化: ```cpp class AI { public: AI() { network = new QNetwork(128, 64, 10); } // 动态分配 ~AI() { delete network; } private: QNetwork* network; // 使用指针 }; ``` > 关键点:**始终通过初始化列表为没有默认构造函数的成员对象显式提供参数**,这是C++对象构造的核心规则之一[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值