Вы должны поместить определение функции в файл .cpp.Поэтому создайте gui.cpp со следующим содержимым:
#include "gui.h"
Gui::Gui(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
}
, удалив его из файла .h.
Причина, по которой вы получили ошибку, заключается в том, что файл заголовка был включен в болеечем один файл .cpp (ваши main.cpp и moc_gui.cpp, сгенерированный файл), и поскольку определение функции было в заголовочном файле, оно было многократно определено.
О, не забудьте добавить новыйФайл .cpp для вашего проекта.Если вы забудете, вы получите ошибки в связи с неопределенными функциями!
@ cbamber85 оставил несколько хороших комментариев по вашему первоначальному вопросу.Хотя в этом случае ваши проблемы не вызваны отсутствием нескольких защитных устройств по мере того, как ваши проекты становятся больше, вы можете столкнуться с проблемами, поэтому привыкание теперь будет полезным.Чтобы защитить файл gui.h от многократного включения, сделайте следующее:
#ifndef GUI_H_
#define GUI_H_
#include "ui_ui.h"
class Gui : public QWidget
{
Q_OBJECT
public:
Gui(QWidget *parent=0);
private:
Ui::Form ui;
};
#endif
Фактическое имя макроса GUI_H_
не имеет значения, вы можете использовать SnOOpy
, но для каждого заголовка вам нужно иметь другое имяТаким образом, использование некоторых вариаций имени файла является обычной практикой.Также общепринятым является использование только заглавных букв в макросах #define
d (просто соглашение; компилятору все равно).
Во многих современных компиляторах вы можете просто использовать:
#pragma once
#include "ui_ui.h"
class Gui : public QWidget
{
Q_OBJECT
public:
Gui(QWidget *parent=0);
private:
Ui::Form ui;
};
ОК, так что это за множественное включение и когда оно происходит?Предположим, у вас есть файл с именем types.h, в котором определены некоторые основные типы, которые вы часто используете.Теперь предположим, что у вас есть два класса Foo и Bar, каждый из которых использует типы из types.h.Вот как это может выглядеть:
Файл: types.h
typedef int Int32;
Файл: foo.h
#include "types.h"
class Foo
{
Int32 mCount;
};
Файл: bar.h
#include "types.h"
class Bar
{
Int32 mLength;
};
Обратите внимание, что я пропустил несколько охранников включения.Теперь предположим, что у меня есть main, который использует и Foo, и Bar:
#include "foo.h"
#include "bar.h"
int main(int argc, const char* argv[])
{
Foo f;
Bar b;
return 0;
}
При отсутствии нескольких защитников включения это будет жаловаться, что Int32 определяется множественно ... В чем проблема?Хорошо, поскольку main.cpp включает в себя foo.h, а foo.h включает types.h, он включается один раз туда и тогда, когда включается bar.h, он также включает types.h, поэтому он включается second раз.
Надеюсь, все это имеет смысл.Я намеренно не учел его в своем первоначальном ответе, но в свете комментариев, вероятно, лучше объяснить его.