Ошибка компиляции при использовании подхода с одним наследованием [Qt Newbie] - PullRequest
0 голосов
/ 08 мая 2011

Я программист PyQt и пытаюсь изучать C ++ Qt.

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

[utdmr@utdmr-arch cpp]$ qmake -project && qmake && make
/usr/bin/uic ui.ui -o ui_ui.h
g++ -c -m64 -pipe -march=x86-64 -mtune=generic -O2 -pipe -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt/mkspecs/linux-g++-64 -I. -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include -I. -I. -I. -o main.o main.cpp
/usr/bin/moc -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt/mkspecs/linux-g++-64 -I. -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include -I. -I. -I. gui.h -o moc_gui.cpp
g++ -c -m64 -pipe -march=x86-64 -mtune=generic -O2 -pipe -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt/mkspecs/linux-g++-64 -I. -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include -I. -I. -I. -o moc_gui.o moc_gui.cpp
g++ -m64 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,-O1 -o cpp main.o moc_gui.o    -L/usr/lib -lQtGui -lQtCore -lpthread 
moc_gui.o: In function `Gui::Gui(QWidget*)':
moc_gui.cpp:(.text+0x80): multiple definition of `Gui::Gui(QWidget*)'
main.o:main.cpp:(.text+0x0): first defined here
moc_gui.o: In function `Gui::Gui(QWidget*)':
moc_gui.cpp:(.text+0x80): multiple definition of `Gui::Gui(QWidget*)'
main.o:main.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status
make: *** [cpp] Error 1

Но я не вижу этого множественного определения в моем коде. Я также новичок в наследовании классов C ++.

Вот мои файлы:

gui.h:

#include "ui_ui.h"

class Gui : public QWidget
{
    Q_OBJECT

    public:
        Gui(QWidget *parent=0);
    private:
        Ui::Form ui;
};


Gui::Gui(QWidget *parent)
        : QWidget(parent)
{
          ui.setupUi(this);
}

main.cpp:

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

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

    Gui gui;
    gui.show();

    return app.exec();
}

ui_ui.h: http://paste.kde.org/56251/ (я использовал pastebin, потому что он длинный)

Спасибо.

Ответы [ 2 ]

3 голосов
/ 08 мая 2011

Вы должны поместить определение функции в файл .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 раз.

Надеюсь, все это имеет смысл.Я намеренно не учел его в своем первоначальном ответе, но в свете комментариев, вероятно, лучше объяснить его.

1 голос
/ 08 мая 2011

Эта часть:

Gui::Gui(QWidget *parent)
    : QWidget(parent)
{
      ui.setupUi(this);
}

должна быть в файле .cpp.В противном случае он будет включен во все объектные файлы, которые включают этот заголовок.(Вы могли бы поместить это в main.cpp, чтобы начать, но было бы более обычно поместить это в отдельный gui.cpp.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...