C++. Qt. Forward declaration. One way to get access to the parent form from a child form

При работе с Qt встала задача: как правильно организовать доступ к данным родительской формы из дочерней формы. Был выбран вариант передачи указателя на экземпляр данной формы в конструктор дочерней формы. В этом случае у Вас может возникнуть следующая проблема. Для родительской формы вы подключаете заголовочный файл определения класса дочерней формы. Но и дочернему классу нужно сообщить о классе (типе) родительской формы. Если подключить заголовочный файл определения класса родительской формы, то возникнет ситуация циклического подключения этих заголовочных файлов. Чтобы этого избежать, необходимо воспользоваться техникой "опережающего определения" (forward declaration):

bar.h

#include "foo.h"

class bar {
public:
    bar();
};

bar.cpp

bar::bar() {
    foo f ();
    // work with object f
}

foo.h

class bar; // forward declaration

class foo {
public:
    foo(bar* obj); // pointer or a reference
};

foo.cpp

#include "bar.h"
#include "foo.h"

foo::foo(bar* obj) {
    // work with pointer obj
}

Ниже приведен пример данного подхода, в котором дочерняя форма при отрисовке таблицы со списком элементов обращается к соответствующему списку родительской формы.

item.h

#ifndef ITEM
#define ITEM

#include <QString>

class Item {
private:
    int id;
    QString description;

public:
    Item(int id, QString description) : id(id), description(description) {}

    void setId(int id) {
        this->id = id;
    }

    int getId() const {
        return id;
    }

    void setDescription(QString description) {
        this->description = description;
    }

    QString getDescription() const {
        return description;
    }
};

#endif

mainwindow.h

#ifndef MAINWINDOW
#define MAINWINDOW

#include <QMainWindow>
#include "itemswindow.h"
#include "item.h"

class MainWindow : public QMainWindow {
Q_OBJECT

public:
    MainWindow(QWidget* wgt = 0);
    QList<Item> itemList;

public slots:
    void slotItems();
};

#endif

mainwindow.cpp

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

MainWindow::MainWindow(QWidget* wgt) : QMainWindow(wgt) {
    QMenu* menu = new QMenu("Menu");
    menu->addAction("Exit", qApp, SLOT(quit()));
    menuBar()->addMenu(menu);

    // central widget
    QWidget* centralWidget = new QWidget;

    QVBoxLayout* buttonsWidgetLayout = new QVBoxLayout(centralWidget);
    buttonsWidgetLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);

    QPushButton* itemsBttn = new QPushButton("Items");
    itemsBttn->setFixedWidth(150);
    buttonsWidgetLayout->addWidget(itemsBttn);

    connect(itemsBttn, SIGNAL(clicked()), SLOT(slotItems()));

    setCentralWidget(centralWidget);
    setWindowTitle("MainWindow");

    // for testing
    itemList.append(Item(1, "First item"));
    itemList.append(Item(2, "Second item"));
    itemList.append(Item(3, "Third item"));
    itemList.append(Item(4, "Fourth item"));
    itemList.append(Item(5, "Fifth item"));
}

void MainWindow::slotItems() {
    ItemsWindow* itemsWindow = new ItemsWindow(this, this);
    itemsWindow->exec();
    delete itemsWindow;
}

itemswindow.h

#ifndef ITEMSWINDOW
#define ITEMSWINDOW

#include <QtWidgets>
#include <item.h>

class MainWindow;

class ItemsWindow : public QDialog {
Q_OBJECT

private:
    QTableWidget* table;

public:
    ItemsWindow(MainWindow* mw = 0, QWidget* wgt = 0);
};

#endif

itemswindow.cpp

#include "mainwindow.h"
#include "itemswindow.h"

ItemsWindow::ItemsWindow(MainWindow* mw, QWidget* wgt) :
    QDialog(wgt, Qt::WindowTitleHint | Qt::WindowCloseButtonHint) {

    QVBoxLayout* verticalLayout = new QVBoxLayout;
    QHBoxLayout* horizontalBottomLayout = new QHBoxLayout;

    QPushButton* okBttn = new QPushButton("&OK");
    okBttn->setFixedWidth(60);

    connect(okBttn, SIGNAL(clicked()), SLOT(accept()));
    
horizontalBottomLayout->setAlignment(Qt::AlignRight);
horizontalBottomLayout->addWidget(okBttn);

    table = new QTableWidget();
    table->setColumnCount(2);

    QStringList list;
    list << "Id" << "Description";
    table->setHorizontalHeaderLabels(list);
table->setEditTriggers(QAbstractItemView::NoEditTriggers);

    if (mw != NULL && !mw->itemList.empty()) {
        int itemsCnt = mw->itemList.count();
        table->setRowCount(itemsCnt);

        QTableWidgetItem* tableItem = 0;
        for (int i = 0; i < itemsCnt; i++) {
            Item item = mw->itemList.at(i);

            tableItem = new QTableWidgetItem(QString::number(item.getId()));
            tableItem->setTextAlignment(Qt::AlignCenter);
            table->setItem(i, 0, tableItem);

            tableItem = new QTableWidgetItem(item.getDescription());
            table->setItem(i, 1, tableItem);
        }
    }

    this->setWindowTitle("Items");
    verticalLayout->addWidget(table);
    verticalLayout->addLayout(horizontalBottomLayout);
    setLayout(verticalLayout);
}

main.cpp

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

int main(int argc, char** argv) {
    QApplication app(argc, argv);

    MainWindow window;
    window.show();

    return app.exec();
}

Исходники доступны по данной ссылке - source.