Question

I've got an unelegant chunk of C++ Qt code where main creates a graphics item (the parent) which creates a bunch of child graphics items. The child and parent have to call each others methods, i.e. the parent needs to tell its children to do some things (move, change color, etc), and the children will signal the parent to do things to its other children. Having both call each others' methods is leading to some ugly circular code, and it's getting frustrating dodging C2027 errors. Would it make any sense to use a custom signal/slot system as a method of communication between the child and parent? Or should I stay the course with my current design and just try and solve these kinds of bugs?

For example, this code (my current design) generates C2027:

Mainwindow:

#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();
}

Foo:

#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()
{
    ...
}

Bar:

#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();
    ...
}
Was it helpful?

Solution

Yes, that's precisely what signals and slots are for.

Right now you have Bar::someFunction() which calls Foo::doSomething()

What you can do instead is:

  1. Declare doSomething() as a slot
  2. Have Bar emit a signal somethingHappened()
  3. When creating the children, connect their somethingHappened() signal to the parent's doSomething() slot

This is an example of dependency injection, and it allows you to swap the parent class for something else in the future without having to change Bar at all.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top