forward declarations give errors + I want some explanation
-
wrote on 20 Jan 2016, 19:06 last edited by SweetOrange
Hi I am using the find example from "C++ Gui programming with Qt" book chapter 2.
There is the file finddialog.h :#ifndef FINDDIALOG_H #define FINDDIALOG_H #include <QDialog> class QCheckBox; class QLabel; class QLineEdit; class QPushButton; class FindDialog : public QDialog { Q_OBJECT public: FindDialog(QWidget *parent = 0); signals: void findNext(const QString &str, Qt::CaseSensitivity cs); void findPrevious(const QString &str, Qt::CaseSensitivity cs); private slots: void findClicked(); void enableFindButton(const QString &text); private: QLabel *label; QLineEdit *lineEdit; QCheckBox *caseCheckBox; QCheckBox *backwardCheckBox; QPushButton *findButton; QPushButton *closeButton; }; #endif
I get errors with the class forward declarations at beginning of code.
http://s13.postimg.org/jilgxzcsn/1_20_2016a.jpgI have included in project file the line
QT += widgets
finddialog.cpp:
#include <QtGui> #include "finddialog.h" FindDialog::FindDialog(QWidget *parent) : QDialog(parent) { label = new QLabel(tr("Find &what:")); lineEdit = new QLineEdit; label->setBuddy(lineEdit); caseCheckBox = new QCheckBox(tr("Match &case")); backwardCheckBox = new QCheckBox(tr("Search &backward")); findButton = new QPushButton(tr("&Find")); findButton->setDefault(true); findButton->setEnabled(false); closeButton = new QPushButton(tr("Close")); connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(enableFindButton(const QString &))); connect(findButton, SIGNAL(clicked()), this, SLOT(findClicked())); connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QHBoxLayout *topLeftLayout = new QHBoxLayout; topLeftLayout->addWidget(label); topLeftLayout->addWidget(lineEdit); QVBoxLayout *leftLayout = new QVBoxLayout; leftLayout->addLayout(topLeftLayout); leftLayout->addWidget(caseCheckBox); leftLayout->addWidget(backwardCheckBox); QVBoxLayout *rightLayout = new QVBoxLayout; rightLayout->addWidget(findButton); rightLayout->addWidget(closeButton); rightLayout->addStretch(); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addLayout(leftLayout); mainLayout->addLayout(rightLayout); setLayout(mainLayout); setWindowTitle(tr("Find")); setFixedHeight(sizeHint().height()); } void FindDialog::findClicked() { QString text = lineEdit->text(); Qt::CaseSensitivity cs = caseCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive; if (backwardCheckBox->isChecked()) { emit findPrevious(text, cs); } else { emit findNext(text, cs); } } void FindDialog::enableFindButton(const QString &text) { findButton->setEnabled(!text.isEmpty()); }
main.cpp:
#include <QApplication> #include "finddialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); FindDialog *dialog = new FindDialog; dialog->show(); return app.exec(); }
QT += widgets TEMPLATE = app HEADERS = finddialog.h SOURCES = finddialog.cpp \ main.cpp
-
hi
when you say
class QLabel;
its ok to use it for pointers.QLabel *myname;
But if you start to use ANYTHING in it
like
myname->setBuddythen a forward is NOT enough and u must include the include file for it
#include <QLabel>So that is what incomplete class error means.
as you only tell it the name. and if u use more than name, you must give compiler the full class definition.
-
wrote on 20 Jan 2016, 20:05 last edited by
In addition to what @mrjj said, it's a good practice to use forward declaration in your .h file, but you have to add #include <QLabel> in your .cpp for the reasons mrjj gave you. Indeed, the compiler is complaining about your .cpp file, not your .h file.
But for instance, if you don't use a pointer for your variable, or if you inherit from an other class, then you have to #include it, since the compiler needs to know extra information about the content of the class.
-
hi
when you say
class QLabel;
its ok to use it for pointers.QLabel *myname;
But if you start to use ANYTHING in it
like
myname->setBuddythen a forward is NOT enough and u must include the include file for it
#include <QLabel>So that is what incomplete class error means.
as you only tell it the name. and if u use more than name, you must give compiler the full class definition.
wrote on 20 Jan 2016, 20:06 last edited by SweetOrange@mrjj
I added the #includes at finddialog.h:#ifndef FINDDIALOG_H #define FINDDIALOG_H #include <QDialog> #include <QCheckBox> #include <QLabel> #include <QLineEdit> #include <QPushButton> class QCheckBox; class QLabel; class QLineEdit; class QPushButton; class FindDialog : public QDialog { Q_OBJECT public: FindDialog(QWidget *parent = 0); signals: void findNext(const QString &str, Qt::CaseSensitivity cs); void findPrevious(const QString &str, Qt::CaseSensitivity cs); private slots: void findClicked(); void enableFindButton(const QString &text); private: QLabel *label; QLineEdit *lineEdit; QCheckBox *caseCheckBox; QCheckBox *backwardCheckBox; QPushButton *findButton; QPushButton *closeButton; }; #endif
Do I need the forward declarations anymore?
Also I get the errors:
http://s11.postimg.org/4izv8mff7/1_20_2016b.jpg
which I suspect that I haven't included the include files for QHBoxLayout and QVBoxLayout.
In which file do I include these? -
@mrjj
I added the #includes at finddialog.h:#ifndef FINDDIALOG_H #define FINDDIALOG_H #include <QDialog> #include <QCheckBox> #include <QLabel> #include <QLineEdit> #include <QPushButton> class QCheckBox; class QLabel; class QLineEdit; class QPushButton; class FindDialog : public QDialog { Q_OBJECT public: FindDialog(QWidget *parent = 0); signals: void findNext(const QString &str, Qt::CaseSensitivity cs); void findPrevious(const QString &str, Qt::CaseSensitivity cs); private slots: void findClicked(); void enableFindButton(const QString &text); private: QLabel *label; QLineEdit *lineEdit; QCheckBox *caseCheckBox; QCheckBox *backwardCheckBox; QPushButton *findButton; QPushButton *closeButton; }; #endif
Do I need the forward declarations anymore?
Also I get the errors:
http://s11.postimg.org/4izv8mff7/1_20_2016b.jpg
which I suspect that I haven't included the include files for QHBoxLayout and QVBoxLayout.
In which file do I include these?wrote on 20 Jan 2016, 20:08 last edited by ValentinMicheletLook at the file on the right of the error message, you'll know where to #include what the compiler lacks.
-
Hi in 99% of all cases the include has same name as class.
#include <QVBoxLayout>
and no, no need for forward when u use the real include. -
wrote on 20 Jan 2016, 20:22 last edited by
Maybe it's a bit technical, but here is a link on Stack Overflow explaining what a forward declaration is:
http://stackoverflow.com/questions/553682/when-can-i-use-a-forward-declarationBasically, a forward declaration is only a "Don't worry compiler, this class exists." statement. As soon as the implementation of the class is required, the #include is mendatory.
The question of "should I use #include or forward declaration here?" is off topic tho.
-
wrote on 20 Jan 2016, 20:35 last edited by
Thanks for the info.
#ifndef FINDDIALOG_H #define FINDDIALOG_H #include <QDialog> #include <QLabel> #include <QLineEdit> #include <QCheckBox> #include <QPushButton> //class QCheckBox; //class QLabel; //class QLineEdit; //class QPushButton; class FindDialog : public QDialog { Q_OBJECT public: FindDialog(QWidget *parent = 0); signals: void findNext(const QString &str, Qt::CaseSensitivity cs); void findPrevious(const QString &str, Qt::CaseSensitivity cs); private slots: void findClicked(); void enableFindButton(const QString &text); private: QLabel *label; QLineEdit *lineEdit; QCheckBox *caseCheckBox; QCheckBox *backwardCheckBox; QPushButton *findButton; QPushButton *closeButton; }; #endif
#include <QtGui> #include "finddialog.h" #include <QHBoxLayout> #include <QVBoxLayout> FindDialog::FindDialog(QWidget *parent) : QDialog(parent) { label = new QLabel(tr("Find &what:")); lineEdit = new QLineEdit; label->setBuddy(lineEdit); caseCheckBox = new QCheckBox(tr("Match &case")); backwardCheckBox = new QCheckBox(tr("Search &backward")); findButton = new QPushButton(tr("&Find")); findButton->setDefault(true); findButton->setEnabled(false); closeButton = new QPushButton(tr("Close")); connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(enableFindButton(const QString &))); connect(findButton, SIGNAL(clicked()), this, SLOT(findClicked())); connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QHBoxLayout *topLeftLayout = new QHBoxLayout; topLeftLayout->addWidget(label); topLeftLayout->addWidget(lineEdit); QVBoxLayout *leftLayout = new QVBoxLayout; leftLayout->addLayout(topLeftLayout); leftLayout->addWidget(caseCheckBox); leftLayout->addWidget(backwardCheckBox); QVBoxLayout *rightLayout = new QVBoxLayout; rightLayout->addWidget(findButton); rightLayout->addWidget(closeButton); rightLayout->addStretch(); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addLayout(leftLayout); mainLayout->addLayout(rightLayout); setLayout(mainLayout); setWindowTitle(tr("Find")); setFixedHeight(sizeHint().height()); } void FindDialog::findClicked() { QString text = lineEdit->text(); Qt::CaseSensitivity cs = caseCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive; if (backwardCheckBox->isChecked()) { emit findPrevious(text, cs); } else { emit findNext(text, cs); } } void FindDialog::enableFindButton(const QString &text) { findButton->setEnabled(!text.isEmpty()); }
#include <QApplication> #include "finddialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); FindDialog *dialog = new FindDialog; dialog->show(); return app.exec(); }
Now works and compiles properly and runs.
Some explanations though that I found the book lacks. What does the header of the constructor means in finddialog.cpp ?
FindDialog::FindDialog(QWidget *parent) : QDialog(parent)
This is class inheritance as far as I understand it
-
Hi
FindDialog::FindDialog(QWidget *parent)
: QDialog(parent) <---- here we call base class constructor with the parent.This is need to setup the part of the class we get from the base class.
if u have
class A :Bthen some of A is from B and it might need to do stuff in its constructor.
so we call it also. -
wrote on 20 Jan 2016, 20:53 last edited by
Tell me if I am wrong...
QDialog is derived from QWidget.
The FindDialog constructor is typical of Qt widget classes. The parent parameter specifies the parent widget. The default is a null pointer meaning that the dialog has no parent
when we have
FindDialog::FindDialog(QWidget *parent) : QDialog(parent)
we just say that QDialog is the parent of FindDialog and as mentioned above QWidget is the parent of QDialog.
-
Tell me if I am wrong...
QDialog is derived from QWidget.
The FindDialog constructor is typical of Qt widget classes. The parent parameter specifies the parent widget. The default is a null pointer meaning that the dialog has no parent
when we have
FindDialog::FindDialog(QWidget *parent) : QDialog(parent)
we just say that QDialog is the parent of FindDialog and as mentioned above QWidget is the parent of QDialog.
wrote on 20 Jan 2016, 21:07 last edited by ValentinMicheletJust to be sure that you don't mix up "C++ parent class" and "Qt parent mechanism".
In pure C++, a class can inherit from a parent class:
class QDialog: public QWidget {}
Here the QDialog inherits from QWidget.
In Qt, there is a mechanism that makes your life easier for memory managment. You give your class a parent to let it handle the memory in destruction. If you code in C++, you may know that there is no garbage collector as there is in other languages (Java for instance). So as soon as you create an object dynamically - on the heap - using "new" operator, you are responsible for it's destruction using "delete". Qt enables you not to worry about deletion: give your object a parent, and the memory will be handle at its destruction.
FindDialog::FindDialog(QWidget *parent): QDialog(parent)
Here we call the parent constructor (QDialog) with the parent parameter and we let Qt handle destruction, as well as a provide a way to potential future inherited classes to enjoy this mechanism.
-
Hi,
To add to my fellows, you should move:
#include <QDialog> #include <QLabel> #include <QLineEdit> #include <QCheckBox> #include <QPushButton>
in your implementation file. That's were they are needed in your case.
Note that you are using
#include <QtGui>
, while good for rapid prototyping it's a module wide include which means it will pull in all headers from said module thus your compilation time will increase since all files are going to be parsed.
1/12