Qt:信号和插槽与C++:消息传递
Qt:Signals and Slots vs C++:Message Passing
我有两个类
class Car
{
// class Car related methods
public:
setDriversName(QString);
private:
String driversName_; // This information comes from class DriversName
//Must get the drivers name info, when a particular event in this object occurs;
}
class DriversName
{
//class DriversName related methods
String getDriversName();
private:
String driversName_;
}
所以,现在我想在两个类之间进行通信,更具体地说,我希望类Car
在 Car Object 中出现特定事件时从DriversName
类中获取驱动程序的名称。
到目前为止,我有两种方法,
C++ Message passing:
class Car
{
// class Car related methods
public:
setDriversNameObject(DriversName& );
setDriversName()
{
driversName_ = DriversName.getDriversName();
}
private:
DriversName driversName_; // So after setting the Driverclass object, i can directly
//access the driver's name, whenever the event occurs
String driversName_;
}
class DriversName
{
//class DriversName related methods
String getDriversName();
private:
DriversName driversName_;
}
或
Qt
In mainWindow class:
connect(carObject,eventHasOccured(),this,updateDriversName());
void MainWindow::updateDriversName()
{
carObject->setDriversName(driversNameObject.getDriversName);
}
Class Car
{
Q_OBJECT
signals:
emit eventHasOccured();
public:
setDriversNameObject(DriversName& );
private:
DriversName driversName_;
}
Class DriversName
{
Q_OBJECT
String getDriversName();
private:
DriversName driversName_;
}
这两种解决方案肯定会起作用。以下是我的问题:
1)上述方法在OO方面是否存在任何缺陷 原则。
2)这种情况最标准的方式是什么 处理?
3)有没有其他更好的方法来处理给定的 情况。
谢谢。
1)上述方法在OO原则方面是否存在任何缺陷。
第一种方法将Car
方法与DriversName
类紧密结合。
第二个将您的应用程序与Qt耦合。如果您无论如何都在整个应用程序中使用它,那不是什么大问题,但应该考虑。此外,它将业务逻辑代码移动到主窗口类中,这可能不是一个好主意。
2)处理这种情况最标准的方式是什么?
没有"一种确定的方法"可以做到这一点。只是更好和更坏的。
3)是否有其他更好的方法来处理给定的情况。
对于"纯C++"方法,可以引入一个抽象接口来侦听驱动程序名称更改(或者更通用地用于侦听泛型名称更改)。我在这里指的是基本上实现观察者模式。例如,简化的实现可能如下所示:
class NameChangeListener
{
public:
virtual void onNameChange(std::string const & newName) =0;
};
// This assumes change is initiated in DriversName class - not sure if this is correct
// Your code doesn't show the actual triggering of the change
class DriversName
{
public:
// ... other stuff
setNameChangeListener(NameChangeListener* ncl)
{
changeListener = ncl;
}
void setName(std::string const & newName)
{
// ... other stuff
if (changeListener)
changeListener->onNameChange(newName);
}
private:
// ..
NameChangeListener* changeListener;
};
class Car: public NameChangeListener
{
public:
// ... other stuff
void onNameChange(std::string const & newName) {
driversName = newName;
}
};
// somewhere outside:
Car c1;
DriversName n;
n.setNameChangeListener(c1);
对于Qt方法,最好引入一个额外的"Controller"类来封装这种关系,而不是直接在主窗口中执行此操作。
除了nyarlathotep的回答之外,还有一些细节:
1)如果您确实需要在发生特定事件时进行更新,那么第一个解决方案是不够的,因为它不处理事件;应该明确地称Car
setDriversName()
。您确实需要一个信号/时隙,或者一般的回调机制,就像第二种解决方案一样。在这种情况下,我认为您宁愿需要类似的东西
connect(driversNameObject,nameChanged(string),carObject,setDriversName(string));
其中应用程序/主窗口和carObject
都不需要知道有关driversNameObject
的任何信息。除此之外,我认为您的第二个解决方案中存在许多小错误(例如,Car
中没有setDriversName
方法.
2)和3)如果我还没有在QT项目中工作,我个人会避免使用QT的信号/插槽机制。此机制完全绕过C++语言,需要通过其自己的工具对源文件进行预处理。一个结果是,在编译器有机会检查之前,所有内容(如方法名称)都作为字符串进行处理。另一个是你需要一种特定的方式来构建你的项目,这种方式比必要的复杂得多,并且会使使用其他库更加困难。
至于更"纯C++"的解决方案,我敢打赌,例如Boost.Signals可以完成这项工作,但它可能会带来太多你不需要的复杂性。
我开发了一个纯C++抽象接口,它完全模仿基于委托的QT信号/插槽的行为,但这涉及内部的低级内容,例如投射到void*
。另一种选择当然是在内部使用std::function
。在处理所有函数调用语言功能方面,它仍然不是完全通用的,例如派生类中的方法、重载、虚拟方法、默认参数等(但 Boost.Signals 也不是)。我打算在完成之前使用 C++11 中的可变参数模板重新实现它。
同样,我(仍然)不知道一个完美或事实上的标准解决方案。
- Libmosquitto publish 不会将所有消息传递到 Azure IoT Hub
- 线程消息传递或更好:在"大师班"中访问其他班级的成员
- 如何在 boost::asio 中将打包的结构作为消息传递?(无序列化)
- "Guaranteed Delivery"消息传递 - 我应该使用 MQTT 还是 ZeroMQ?
- 核心消息传递中未处理的异常.dll在程序关闭期间
- Microsoft具有本机消息传递和非持久连接的边缘扩展不起作用
- Firebase C 云消息传递背景问题
- 从客户端到浏览器的CEF中的消息传递序列化
- 我们是否可以使用 FireBase 云消息传递来发送或接收消息,或者在 Windows 桌面/控制台或 Linux 控制
- 如何将WM_KEYDOWN消息传递到 IWebBrowser2 实例
- 如何在 GNU Radio 中实现消息传递
- msgpack:C++和Java之间的消息传递
- 增强ASIO和线程之间的消息传递
- 交流时Chrome本机消息传递错误
- 多线程C++消息传递
- 跨平台最佳 MVC 模型到控制器消息传递方法(C#、Objective-C++)
- 如何在Chrome原生消息传递扩展的本机应用程序中使用本机主机消息
- 移动窗口(),跳过,躲避或绕过消息传递
- 无效输入会导致多语言 JSON 消息传递系统中的身份验证绕过
- 共享内存系统性能的消息传递接口