C++ QT 在类结构中传递更高消息的最佳方法

Posted

技术标签:

【中文标题】C++ QT 在类结构中传递更高消息的最佳方法【英文标题】:C++ QT best way to pass a message higher in class structure 【发布时间】:2021-08-18 09:23:33 【问题描述】:

我目前正在实现一个程序,在QT中实现PC程序与外部设备之间的TCP通信。我遇到的问题比较笼统,但我会以这个为例。

我的类层次结构如下所示:

            Program
           /       \
      Server_A <--> Server_B <--- External system
          |
       Sockets[]
       /        \
  Commands      Confirmations
                /     |     \
         Interf1   Interf2    Interf3

我可以从设备(Socket)获取命令,我的命令进入Confirmation 类,实现任何Interface 作业,并将确认返回给Socket,后者将其发送回设备。

当我想从外部系统发送命令时会出现问题,我也必须确认。

    我在Server_B 上收到一条消息并将其传递给Server_A,其中包含以下信息:socket 发送命令和命令实现。 我将命令传递给特定的socket SocketCommands 发送命令,因为存在外部系统命令的逻辑。 Commands 准备消息,运行逻辑,并(通过套接字)向设备发送消息 Socket 等待回复 Socket 得到响应,知道它是对外部系统命令的响应,并将其传回给Commands Commands 实现了它的逻辑。

这里一切都会好的,但下一步是:

    Commands 需要向外部系统确认成功(或失败)。

所以基本上,我要做的就是通过这种方式将消息从Commands 传递给Server_BCommands-&gt;Socket-&gt;Server_A-&gt;Server_B。对于所有这些类,我必须创建一个不必要的方法来传递这一信息。有没有办法以某种方式解决这个问题?在我的编程过程中,经常需要将一些东西传递给我的类结构的更高层,而通过仅进一步传递信息的附加方法来实现它似乎是多余的。

我已经为这个问题提供了一个示例伪代码:

class Program

    ServerB serverB;
    ServerA serverA;


class ServerB

    void send(QString msg);


class ServerA

    QVector<MySocket*> sockets;


class MySocket

    Commands commands;
    Confirmations confirmations;


class Commands

    void doLogic();
    void sendToExternalSystem(QString message); //How to realize it?


我的程序要大得多,但我希望它能让您了解我想要实现的目标。最简单的解决方案是在 Sockets、Server_A 和 Server_B 中添加一个方法 void sendToExternalSystem(QString message),并在构造期间为每个父级提供一个指针(命令将有权访问套接字,套接字将有权访问 server_a,而 server_a 将有权访问server_b)

【问题讨论】:

为什么看起来“可怕”?为什么你认为做一些有用的方法是“不必要的”?你能发布一个小例子来说明这个问题吗?要求避免某些代码而不显示代码是困难的 我使用了“冗余”这个词 :),我提供了简单的伪代码,希望对您有所帮助,但这是我的问题 - 如果 Server_B 是一个全局类,它会很简单(只需运行 Server_B .send(message)),但事实并非如此,我必须通过 4 个不同的对象传递sendToExternalSystem(QString message),我希望我能在保持高质量代码的同时以某种方式解决它,我的问题的重点是我想学习一个解决此类问题的技术,因为它对我来说经常发生,我相信仅仅因为这种情况可能不是最好的解决方案而保存父指针。 答案类型:it is actually the best solution to provide pointers to parent and new methods 就可以了。至于现在,我只是有一种感觉,我这样做会做错事,可以做得更好的事情。 当某物委托其他实体执行会产生结果的任务时,您可以考虑承诺/未来模式 @MatG 我刚刚检查了承诺/未来模式,它看起来是一个很好的解决方案。如果我错了,你能纠正我吗?这是否意味着我必须用消息传递一个承诺,一旦我想重新发送确认,用消息填充它,然后调用完成,在 Server_B 上使用观察者它会产生一个信号,我会能应付吗?我也打算在单线程应用程序上使用它,但我相信这不是观察者信号的问题。 【参考方案1】:

最后,我想出了一个解决方案。必须实现ExternalCommand 类,这些实例是在Server_B 中创建的。

在最小解决方案中,它有:1.字段QString Message,2.方法QString getMessage(),3.方法void finish(QString),4.信号void sendToExternal(QString)

当我在Server_B 中读取外部系统发送的消息时,我创建了该类的一个实例,并将其连接到Server_B 发送方法。在我的代码中,它看起来像这样:

ExternalCommand::ExternalCommand(QString message, QObject* parent) : QObject(parent)

    this->message=message;


QString ExternalCommand::getMessage()

    return this->message;


void finish(QString outputMessage)

    emit sendToExternal(outputMessage);

void Server_B::onReadyRead()

    QTcpSocket *socket = dynamic_cast<QTcpSocket*>(sender());
    QString message = socket->readAll();
    ExternalCommand* cmd = new ExternalCommand(message);
    connect(cmd, &ExternalCommand::sendToExternal, socket, 
        [socket](QString message) socket->write(message.toUtf8()););

还需要在发送命令后在ExternalCommand 中实现某种类型的对象销毁,但这不是这个问题的重点。

所以一旦这个实现,而不是QString的消息,消息会以ExternalCommand*的形式传递给较低的级别,一旦得到答案,就可以将其发送回外部系统,致电ExternalCommand::finish(QString outputMessage);。当然,这只是这个问题的最小解决方案。

感谢 @MatG 向我指出 Promise/Future 模式,这有助于找到此解决方案。

【讨论】:

以上是关于C++ QT 在类结构中传递更高消息的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

在类 C 结构中自动重新排序字段的方法

c++ 以最佳方式返回结构和向量

用于一对一消息传递的 Firebase 数据库结构?

在 python 中匹配 C++ 结构的最佳方法?

在 C++ 中初始化 C 结构

C#和C++传递结构体