Qt 信号槽处理私有变量:特性还是缺陷?

问题描述

我正在使用 Qt 库处理相当冗长的 C++ 代码(超过 70K 行),并且在处理私有变量时遇到了(对我而言)信号槽机制的意外行为。

这个想法是,当一个对象 (object1) 用一个信号与另一个 (object2) 通信时,该信号包括前者的私有变量(object1 的 vec1),后者(object2)能够修改它。我想知道这是必须将其视为功能还是缺陷。

在这里放了一个简化的代码来说明这个事实:object1 有一个名为 vec1(指针)的私有 QVector 变量,并向 object2 发送一个信号以删除 vec1 的一些元素。这个 object2 捕获信号并成功执行任务。

#include "mainwindow.h"
#include <QApplication>

int main(int argc,char *argv[])
{
    QApplication a(argc,argv);
    MainWindow mainWin;
    mainWin.show();
    return a.exec();
}

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLabel>
#include <QVBoxLayout>
#include "object1.h"
#include "object2.h"

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{    
    QVector<int> * vec;
    object1 *obj1 = new object1();
    object2 *obj2 = new object2();

    connect(obj1,SIGNAL(remove_items_signal1(QVector<int>*,int)),obj2,SLOT(remove_items_slot2(QVector<int>*,int)));

    vec = obj1->get_vec1();

    QString str1("vec1 before removing any elements = ");
    for (int i = 0 ; i < vec->length(); i++){
        str1.append(QString(" %1").arg(vec->at(i)));
    }
    QLabel *label1 = new QLabel(str1);

    // remove some elements at the end of the vector using the signal-slot mechanism
    // Notice that the elements of vec1 (which is private of object1) 
    // are removed in object2.

    int i = 3;

    obj1->emit_remove_items(i);

    vec = obj1->get_vec1();

    QString str2("vec1 after removing the last " + QString("%1").arg(i) + " elements in object2 = ");
    for (int i = 0 ; i < vec->length(); i++){
        str2.append(QString(" %1").arg(vec->at(i)));
    }
    QLabel *label2 = new QLabel(str2);

    QVBoxLayout *layout = new QVBoxLayout();
    layout->addWidget(label1);
    layout->addWidget(label2);

    QWidget *window = new QWidget();
    window->setLayout(layout);

    setCentralWidget(window);

}

MainWindow::~MainWindow()
{
}

object1.h

#ifndef OBJECT1_H
#define OBJECT1_H

#include <QWidget>
#include <QVector>

class object1 : public QWidget
{
    Q_OBJECT
public:
    explicit object1(QWidget *parent = 0);
    ~object1();
    void emit_remove_items(int);
    QVector<int> * get_vec1();
signals:
    void remove_items_signal1(QVector<int> *,int);
private:
    QVector<int> *vec1;
};
#endif // OBJECT1_H

object1.cpp

#include "object1.h"

object1::object1(QWidget *parent) : QWidget(parent)
{
    vec1 = new QVector<int>();
    *vec1 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9;
}

object1::~object1(){

}

void object1::emit_remove_items(int i){
    emit remove_items_signal1(vec1,i);
}

QVector<int>* object1::get_vec1(){
    return vec1;
}

object2.h

#ifndef OBJECT2_H
#define OBJECT2_H

#include <QWidget>
#include <QVector>

class object2 : public QWidget
{
    Q_OBJECT
public:
    explicit object2(QWidget *parent = 0);
    ~object2();
public slots:
    void remove_items_slot2(QVector<int> *,int);
private:
    QVector<int> *vec2;
};
#endif // OBJECT2_H

object2.cpp

#include "object2.h"

object2::object2(QWidget *parent) : QWidget(parent)
{
   vec2 = new QVector<int>();
}

object2::~object2(){

}

void object2::remove_items_slot2(QVector<int> * vec1,int i){
    vec2 = vec1;
    if (i < vec2->length()){
        int j = vec2->length()-i;
        vec2->remove(j,i);
    }
}

解决方法

这并不奇怪,因为信号/插槽正在做一些奇怪的事情。您的成员函数 object1::emit_remove_items 将对私有成员 vec1 的引用传递给信号 remove_items_signal1(这只是另一个函数)。将此信号连接到插槽使信号实现调用该插槽(这只是另一个函数)。

您对信号/槽模式的使用有点奇怪,因为您将 object1 的私有部分泄露给 object2,正如您所注意到的,这破坏了封装。

最好的做法是:

  1. 函数名称反映了函数的作用,而不是它们第一次编写时的使用方式,
  2. 信号是被动命名的,例如somethingChangedsomethingEnded
  3. 槽,或者实际上所有的函数,都是主动命名的,例如doSomethingendSomething

应用这些指导方针,然后改变你的代码以实现它们,甚至可能会使奇怪的私有指针传递部分消失。 如果没有,你需要重新思考你到底想要完成什么。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...