简体   繁体   English

Qt:信号和插槽与C ++:消息传递

[英]Qt:Signals and Slots vs C++:Message Passing

I have two classes 我有两节课

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_;
}

So, now i want to communicate between the two classes, more specifically i want class Car to get the driver's name from the DriversName class when a particular event occours in Car Object . 所以,现在我想在两个类之间进行通信,更具体地说, 当Car Object中出现特定事件时 ,我希望类CarDriversName类中获取驱动程序的名称。

So far i have these two ways, 到目前为止,我有这两种方式,

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_;
}

OR 要么

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_;    
}

Both the Solutions will definitely work. 两种解决方案肯定都会有效。 Here are my questions: 这是我的问题:

1) Is there any flaw in the above methods, with respect to OO principles. 1)就OO原则而言,上述方法是否存在任何缺陷。

2) Which is the most standard way this situation can be dealt with ? 2)这种情况可以处理的最标准方法是什么?

3) is there any other better method to handle the given situation. 3)还有其他更好的方法来处理给定的情况。

Thanks. 谢谢。

1) Is there any flaw in the above methods, with respect to OO principles. 1)就OO原则而言,上述方法是否存在任何缺陷。

The first approach couples the Car method closely to the DriversName class. 第一种方法将Car方法与DriversName类紧密DriversName

The second couples your application to Qt. 第二个将您的申请与Qt联系起来。 If you use it throughout your whole application anyway, that's not much of a problem, but it should be considered. 如果你在整个应用程序中使用它,那不是什么大问题,但应该考虑它。 Also, it moves business logic code into the mainwindow class, which might not be such a good idea. 此外,它将业务逻辑代码移动到主窗口类中,这可能不是一个好主意。

2) Which is the most standard way this situation can be dealt with ? 2)这种情况可以处理的最标准方法是什么?

There is no "one definitive way" of doing this. 这样做没有“一种明确的方式”。 Just better and worse ones. 只是越来越好。

3) is there any other better method to handle the given situation. 3)还有其他更好的方法来处理给定的情况。

For the "pure C++" approach, you could introduce an abstract interface for listening to driver name changes (or maybe even more generically for listening to generic name changes). 对于“纯C ++”方法,您可以引入一个抽象接口来监听驱动程序名称更改(或者甚至更一般地用于监听通用名称更改)。 What I'm referring to here is basically implementing the Observer pattern. 我在这里指的是基本上实现Observer模式。 A simplified implementation could eg look like this: 简化的实现可以如下所示:

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);

For the Qt approach, it might be good to introduce an additional "Controller" class encapsulating such relations, instead of doing it directly in the main window. 对于Qt方法,可能最好引入一个封装这种关系的附加“Controller”类,而不是直接在主窗口中进行。

A few more details on top of nyarlathotep's answer: 在nyarlathotep的回答之上还有一些细节:

1) If you definitely need the update to take place when a particular event occurs , then the first solution is not enough because it does not handle events; 1)如果您确实需要在特定事件发生时进行更新,那么第一个解决方案是不够的,因为它不处理事件; one should explicitly call Car 's setDriversName() . 一个人应该明确地调用CarsetDriversName() You do need a signal/slot, or callback mechanism in general, like the second solution. 你需要一般的信号/插槽或回调机制,就像第二种解决方案一样。 It that case, I think you would rather need something like 在那种情况下,我认为你宁愿需要类似的东西

connect(driversNameObject,nameChanged(string),carObject,setDriversName(string));

where neither the application/main window nor the carObject need to know anything about a driversNameObject . 应用程序/主窗口和carObject需要知道有关driversNameObject任何信息。 Besides that, I think there are a number of little errors in your second solution (eg, there is no setDriversName method in Car . 除此之外,我认为你的第二个解决方案中存在一些小错误(例如, Car没有setDriversName方法。

2) and 3) I would personally avoid QT's signal/slot mechanism if I am not already working in a QT project. 2)和3)如果我还没有在QT项目中工作,我个人会避免使用QT的信号/插槽机制。 This mechanism bypasses the C++ language entirely and needs source file preprocessing by its own tools. 这种机制完全绕过C ++语言,需要通过自己的工具进行源文件预处理。 One consequence is that everything (like method names) is processed as a string, before the compiler has any chance for checking. 一个结果是在编译器有任何检查机会之前,所有内容(如方法名称)都被处理为字符串。 Another is that you need a specific way to build your project that is way more complicated than necessary and would make the use of other libraries more difficult. 另一个是你需要一种特定的方式来构建你的项目,这种方式比必要的更复杂,并且会使其他库的使用更加困难。

As for more "pure C++" solutions, I bet eg Boost.Signals would do the job, but again it would probably bring too many complexities that you don't need. 至于更多“纯C ++”解决方案,我敢打赌,例如Boost.Signals会完成这项工作,但同样可能会带来太多你不需要的复杂性。

I have developed a pure-C++ abstract interface that mimics exactly the behavior of QT signals/slots based on delegates , but this involves low-level stuff internally like casting to void* . 我开发了一个纯C ++抽象接口,它完全模仿基于委托的QT信号/槽的行为,但这涉及内部的低级内容,如转换为void* An alternative would be of course to use std::function in the internals. 另一种选择当然是在内部使用std::function It is still not completely generic in handling all function-call language features, eg methods in derived classes, overloading, virtual methods, default arguments, and so on (but neither is Boost.Signals). 它在处理所有函数调用语言特性时仍然不是完全通用的,例如派生类中的方法,重载,虚方法,默认参数等等(但Boost.Signals都不是)。 I intend to re-implement it in C++11 using variadic templates before completing it. 我打算在完成它之前使用可变参数模板在C ++ 11中重新实现它。

Again, I am (still) not aware of a perfect or de facto standard solution. 同样,我(仍)不知道完美或事实上的标准解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM