Использование сигналов/слотов, чтобы избежать циклических зависимостей?

У меня есть неэлегантный кусок кода C++ Qt, где main создает графический элемент (родительский), который создает кучу дочерних графических элементов. Ребенок и родитель должны вызывать методы друг друга, т.е. родитель должен сказать своим дочерним элементам сделать некоторые вещи (переместиться, изменить цвет и т. д.), а дочерние элементы будут сигнализировать родителю о том, чтобы сделать что-то другим своим дочерним элементам. Когда оба вызывают методы друг друга, это приводит к уродливому круговому коду, и становится раздражающим уклонение от ошибок C2027. Имеет ли смысл использовать пользовательскую систему сигналов/слотов в качестве метода связи между дочерним элементом и родителем? Или мне следует придерживаться курса с моим текущим дизайном и просто попытаться решить подобные ошибки?

Например, этот код (мой текущий дизайн) генерирует C2027:

Главное окно:

#include "mainwindow.h"
#include "ui_mainwindow.h"

vector<Foo*> FooArray;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    scene = new QGraphicsScene(this);
    ui->graphicsView->setScene(scene);

    int viewwidth = ui->graphicsView->width();

    ...

    FooArray.push_back(new Foo(5, viewwidth, scene));
    FooArray[0]->loadBars();
}

Фу:

#include "Foo.h"  //includes bar.h


vector<int> ActiveList;
vector<Bar*> BarArray;

Foo::Foo(int id, int w, QGraphicsScene* scene)
{
    this->id = id;
    this->width = w;
    this->scene = scene;
}

...

void Foo::loadBars()
{
    ...
    BarArray.resize(nitems);
    BarArray[k] = new Bar(id, k, this);
    BarArray[k]->setPos(...);
    scene->addItem(BarArray[k]);
    ...
}

void Foo::doSomething()
{
    ...
}

Бар:

#include "Bar.h"  //forward declares Foo; isn't executed until Foo exists. 

Bar::Bar(int setid, int num, Foo* foo)
{
    this->s = setid;
    this->n = num;
    this->owner = foo;
}

...

void Bar::someFunction()
{   
    ...
    owner->doSomething();
    ...
}

person BB ON    schedule 09.01.2014    source источник


Ответы (1)


Да, именно для этого и нужны сигналы и слоты.

Прямо сейчас у вас есть Bar::someFunction(), который вызывает Foo::doSomething()

Что вы можете сделать вместо этого:

  1. Объявить doSomething() слотом
  2. Пусть Бар испускает сигнал somethingHappened()
  3. При создании дочерних элементов подключите их сигнал somethingHappened() к родительскому слоту doSomething().

Это пример внедрения зависимостей, и он позволяет вам заменить родительский класс на что-то другое в будущем без необходимости вообще менять Bar.

person Taylor Brandstetter    schedule 09.01.2014