Confused about Namespaces, auto-generated code by Qt Creator and some C++ syntax
-
First of all, excuse me if this is not the right place to ask, this seemed most reasonable place to me. This is a long post, please bear with me.
I am new to programming, I read C++ tutorials and coded some stupid programs. Now I am learning Qt. I tried hand-coding with a text editor and it felt OK and so far so good. However I am trying to learn Qt Creator too and I am having some difficulty with understanding the automated code that's generated when a new project is created.
I am following from C++ Gui Programming With Qt 4 and trying to implement FindDialog example with Qt Creator, i.e. trying to create it on my own using Designer etc. Everything is OK, until compilation.
The automated code generates the following in the header file which I haven't used when hand-coding by copying from the book:
@namespace Ui {
class FindDialog;
}
@
What I understand from namespaces is that it is a measure to prevent name clashes. That's fine. So is this created because some other classes may be called "FindDialog"? (I am almost positive, just checking.)And in the class declaration, there is the following part:
@private:
Ui::FindDialog *ui;@I am having difficulty understanding this. To me this means, I am creating a FindDialog object (pointer) called ui in the namespace Ui (Well, actually not creating, this is just a trick to leave the definition for later, right?). If I am correct up to this point, may I ask why we create a class with an object of itself inside?
I know this has been so long for you to read, but my real problem starts here:
@FindDialog::FindDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::FindDialog)
{
ui->setupUi(this);
}@Can someone explain to me what's happening here? As far as I understand, this is the constructor function stating FindDialog is inheriting from QDialog but what's the second part? ui was just an object of FindDialog, how/why does it inherit its own class? What's up with "new"? And what are there paranthesis and the arguments there in the first place?
Now to the real show-stopper... The following code gives compilation error, because lineEdit, caseCheckBox, backwardCheckBox and findButton are not declared in this scope:
@
void FindDialog::on_lineEdit_textChanged(const QString &text)
{
findButton->setEnabled(!text.isEmpty());
}void FindDialog::on_findButton_clicked()
{
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);
}
}@By the way, those variables are just elements in Ui form. Setup(this) should have passed them to FindDialog class and hence they should have been in that scope right?
And one final question, by employing namespaces we can use Ui::FindDialog to avoid clashes but how can we refer to FindDialog's members? Is Ui::FindDialog.setWindowTitle("Find") ok?
Please, correct me, teach me and I will be grateful to you.
Thanks.
-
OK, so the first thing to note is that the difference between what they are showing you in the book and what Qt Creator defaults to generating is a small and sort of subtle difference in C++ philosophy: at this point in your career you probably don't want to get too deep into the "why" part of it, you may wind up just being more confused. Suffice it to say that both the book and Qt Creator are using what is called the "Private Implementation" design pattern, but implementing it in slightly different ways.
Your understanding of the namespace, and the forward declaration of FindDialog in the Ui namespace appears to be correct: we use a forward declaration because we're only storing a pointer, and so the compiler doesn't actually need to know anything about the class's internal structure at this point (this saves us from having to include its header file here, and is generally a good practice). So, we define our class as having a pointer to an object of type Ui::FindDialog.
Now, when we get to the constructor, it's easiest to think of this in multiple pieces: @FindDialog::FindDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::FindDialog)@ Of course the first line is just the function definition itself. The second line is where we handle the construction of the parent portion of this class. The third line (and potentially a whole list of other lines, too) initialize the member variables before we enter the actual constructor method. For example, if your class also had an integer in it, like this: @private:
Ui::FindDialog *ui;
int myInt;@ and you wanted that integer to be initialized with some value, you would have: @FindDialog::FindDialog(QWidget *parent) :
QDialog (parent),
ui (new Ui::FindDialog),
myInt (100)@ (for example). In this particular case, you've got a <code>new</code> operator in there because you are allocating a new object of that type, and you can do that right in the initializer. It's functionally equivalent to @FindDialog::FindDialog(QWidget *parent) :
QDialog (parent)
{
ui = new Ui::FindDialog;
}@ though most C++ programmers will tell you that using the initializer form is better (for a number of reasons, some of which are a bit esoteric at this point in your career). -
Now, onto the real problem you are having, which is simply a result of the slight difference in the way the book and Qt Creator implement the Private Implementation pattern. In the book, your class inherits from the UI class; in the code generated by Qt Creator, your class has a private member that implements all the UI stuff. So, when using Qt Creator to follow the book's examples, anytime the book references a widget as though it's just a member variable, e.g. @void FindDialog::on_lineEdit_textChanged(const QString &text)
{
findButton->setEnabled(!text.isEmpty());
}@ your code has to instead access that widget through its private UI object, like this: @void FindDialog::on_lineEdit_textChanged(const QString &text)
{
ui->findButton->setEnabled(!text.isEmpty());
}@ -
The different approaches to use a ui file in your application are described in section "Using a Designer UI File in Your Application":/doc/qt-4.8/designer-using-a-ui-file.html of the Designer manual. Qt Creator uses the single inheritance with a pointer member variable by default. You can change it in the preferences, though.
The namespace for the ui is introduce, because usually you have the plain ui class (Ui:FindDialog) which is generated from Designer's ui file and the actual class that implements the functionality. Both usually have the same stripped name and would clash if there was no namespace.
The find dialogs UI members are dereferenced using the ui pointer: ui->lineEdit. The ui is a pointer to a regular C++ class, and it's treated as such in your code. Once uic has run and created the ui_finddialog.h file, Creator catches up its contents ans provides the usual code completion for the UI components.
-
Nowhere up to this point, I have stumbled such a usage (I mean initializing a variable before entering function scope) thanks for letting me know. But still don't get it completely, where can I read more about that? I am used to initializing between the paranthesis.
I don't feel clear enough as I am confused right now. So one more attempt for my question:
@FindDialog::FindDialog(QWidget *parent)@
is just a function(constructor) that's taking a parent argument of type QWidget pointer.
@ui(new Ui::FindDialog)@
is just
@ui = new Ui::FindDialog;@
However is that a class declaration/definition inside the FindDialog class? And what happens to the ui pointer variable it has in itself? Is it just null, dangling?
And what does QDialog(parent) mean?
I feel like I haven't learnt C++ a bit :S
-
We're talking about the class constructor here - this is different from ordinary methods. You'll find the details in every C++ introduction. You may have a look at the "C++ FAQs":http://www.parashift.com/c++-faq-lite/ too.
Regarding the ui pointer: It is not initialized to a default value (NULL would be handy), but just some space in memory is reserved. It may contain some random data and creates an invalid, dangling pointer here.
QDialog(parent) calls the constructor of your base class (QDialog) with the parent pointer as parameter.
This all is very basic C++ stuff - I highly recommend reading an introduction, especially on inheritance, constructors and member initialization stuff.
-
[quote author="sonay" date="1325115484"]However is that a class declaration/definition inside the FindDialog class? And what happens to the ui pointer variable it has in itself? Is it just null, dangling?
[/quote]
It is not a declaration or definition: it is an instantiation. It allocates a new object of type Ui::FindDialog, and stores a pointer to that object in the variable "ui". At no point within the constructor function itself is ui uninitialized (or null), because it's being set before you even enter that function.[quote]
And what does QDialog(parent) mean?
[/quote]
If you look at the documentation for @QDialog@ you will see that one of its constructors takes a pointer to a QWidget: that widget becomes the dialog's parent, and Qt will then take care of deallocating the dialog when its parent is destroyed. The call to @QDialog(parent)@ in the constructor simply makes sure that the QDialog is properly constructed with the correct parent widget. -
[quote author="Volker" date="1325116217"]
This all is very basic C++ stuff - I highly recommend reading an introduction, especially on inheritance, constructors and member initialization stuff.[/quote]
I don't know what you have read when you were learning but I have read a lot and not one of the books had this kind of initialization. I am sorry to bother you with such basic questions, you may just ignore me. Surely I will study the links you provided. Again, thanks for all your help.
-
[quote author="Chris H" date="1325116308"]
It is not a declaration or definition: it is an instantiation. It allocates a new object of type Ui::FindDialog, and stores a pointer to that object in the variable "ui". At no point within the constructor function itself is ui uninitialized (or null), because it's being set before you even enter that function.[quote]
And what does QDialog(parent) mean?
[/quote]
If you look at the documentation for @QDialog@ you will see that one of its constructors takes a pointer to a QWidget: that widget becomes the dialog's parent, and Qt will then take care of deallocating the dialog when its parent is destroyed. The call to @QDialog(parent)@ in the constructor simply makes sure that the QDialog is properly constructed with the correct parent widget.[/quote]I am sorry, I am not a native speaker. I meant what happens when you instantiate and was confused at that moment, now I got my answer. It is obvious I need to study more instead of keeping you busy. Thanks for your kind and patient answers.
-
[quote author="sonay" date="1325116861"]
I don't know what you have read when you were learning but I have read a lot and not one of the books had this kind of initialization.[/quote]Actually you should always[1] prefer initialization lists over assignments, as it allows the compiler to construct most objects in-place without a temporary object which results in better performance.
[1] "C++ FAQ 10.6":http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.6