2011-11-29 7 views
1
이 코드 링크를 컴파일하고 의도 한대로 작동

:왜 .cpp 파일에 Q_OBJECT 매크로가있는 경우 내 프로젝트가 링크되지 않습니까?

#include <QApplication> 
#include <QListView> 
#include "File_List_Model.h" 

int main(int c,char**v) 
{ 
    QApplication app(c,v); 
    QStringList list; 

    list << "a" << "b" << "c"; 

    File_List_Model* model = new File_List_Model; 
    model->set_entries(list); 

    QListView* view = new QListView; 
    view->setModel(model); 
    view->show(); 

    return app.exec(); 
} 

을하지만 .cpp 파일 대신 헤더 파일에 클래스 정의를 둘 때, 나는 vtable가 제대로 정의되지 않았 음을 알리는 링커 오류를 얻을.

#include <QApplication> 
#include <QListView> 
//#include "File_List_Model.h" 
#include "File_List_Proxy.h" 
#include <QAbstractItemModel> 
#include <QStringList> 

class File_List_Model : public QAbstractItemModel 
{ 
    Q_OBJECT 
private: 
    QStringList data_; 
public: 
    File_List_Model(QObject *parent = 0) : 
     QAbstractItemModel(parent) 
    { 
    } 

    int columnCount(const QModelIndex& parent) const 
    { 
     return 1; 
    } 

    QVariant data(const QModelIndex & index, int role) const 
    { 
     switch(role) 
     { 
      case Qt::DisplayRole: 
      return data_[index.row()]; 
     default: 
      return QVariant(); 
     } 
    } 

    QModelIndex index(int row, int column, const QModelIndex & parent) const 
    { 
     return createIndex(row,column); 
    } 

    QModelIndex parent(const QModelIndex & index) const 
    { 
     return QModelIndex(); 
    } 

    bool set_entries(const QStringList& entries) 
    { 
     if (entries.size()) 
     { 
     beginInsertRows(createIndex(0,0),0,entries.size()); 
     data_ = entries; 
     endInsertRows(); 
     emit dataChanged(createIndex(0,0),createIndex(0,entries.size())); 
     return true; 
     } 
     else 
     { 
      return false; 
     } 
    } 

    int rowCount(const QModelIndex & parent) const 
    { 
     return data_.size(); 
    } 


}; 

int main(int c,char**v) 
{ 
    QApplication app(c,v); 
    QStringList list; 

    list << "a" << "b" << "c"; 

    File_List_Model* model = new File_List_Model; 
    model->set_entries(list); 

    File_List_Proxy* proxy = new File_List_Proxy; 
    proxy->setSourceModel(model); 

    QListView* view = new QListView; 
    view->setModel(proxy); 
    view->show(); 

    return app.exec(); 
} 
//error: 
debug/moc_File_List_Model.o:moc_File_List_Model.cpp:(.rdata$_ZTV15File_List_Model[vtable for File_List_Model]+0x44): undefined reference to `File_List_Model::columnCount(QModelIndex const&) const' 
debug/moc_File_List_Model.o:moc_File_List_Model.cpp:(.rdata$_ZTV15File_List_Model[vtable for File_List_Model]+0x4c): undefined reference to `File_List_Model::data(QModelIndex const&, int) const' 

이 정확히 같은 코드가 될 것으로 보인다. 코드가 헤더에 있고 다른 방식으로 링크하지 않으면 링크되는 이유는 무엇입니까?

답변

3

Qt는 moc 도구를 사용하여 예를 들어 신호 슬롯 메커니즘에 필요한 C++ 확장을 처리합니다. 이 도구는 프로젝트의 모든 헤더 (!) 파일을 처리하고 Q_OBJECT 매크로를 포함하는 클래스의 메타 오브젝트 코드를 포함하는 새 소스 파일을 생성합니다.

.h 파일 대신 .cpp 파일에 정의 된 클래스가있을 때 파일 moc이 올바르게 처리되지 않습니다.

Qt 메타 오브젝트 컴파일러에 대한 자세한 내용은 this article을보십시오.

+0

qmake 및 cmake Qt 지원은 프로젝트에 나열된 모든 소스 파일에서 'Q_OBJECT' 매크로를 포함하는 moc를 호출합니다. 이것은 파일의 확장에 관계없이 발생합니다.질문의 경우 qmake/cmake가 자동으로 수행 할 수 없기 때문에 moc 출력은 컴파일러로 전달되지 않았습니다. –

0

Qt는 헤더 파일에 moc를 실행하고 소스에서 실행하지 않기 때문에.

+0

false : qmake와 cmake는'Q_OBJECT' 매크로를 포함하는 모든 소스 파일에서 moc를 실행합니다. 여기서 수행되지 않은 것은 moc의 출력에서 ​​컴파일러를 실행하는 것입니다. –

-1

링커가 moc 출력을 컴파일 할 때 발생하는 개체 코드가 누락되었다고 불평하고 있습니다. 왜냐하면 moc가 소스 파일을 처리했지만 출력이 오브젝트 파일로 컴파일되지 않았기 때문입니다.

헤더 파일의 경우 빌드 시스템은 여러 번역 단위에 포함될 것으로 간주하며 one definition rule을 위반하지 않습니다. 따라서 moc 출력은 헤더 파일을 포함 할 수 있으며 독립 실행 형 번역 단위로 컴파일됩니다.

그러나 당신이 .cpp 파일 내의 Q_OBJECT 매크로가있는 경우는 MOC 출력은 분리하여 컴파일 할 수 없습니다 : 그것은 당신의 .cpp 파일에서 선언에 액세스 할 수 없습니다, 따라서 컴파일 할 수 없습니다! .cpp 파일은 one definition rule에 위배되므로 2 개의 번역 단위 (moc 출력 및 .cpp 파일)가 동일한 내용을 정의하므로이 파일에도 .cpp 파일을 포함 할 수 없습니다.

대신에 moc의 출력을 .cpp 파일의 끝에 추가해야합니다. 당신이 main.cppO_OBJECT이있는 경우 예를 들어, 파일의 끝에 #include "main.moc"을 추가

// main.cpp 
#include <QtCore> 

struct Object : QObject { 
    Q_OBJECT 
}; 

int main() { 
    Object o; 
    qDebug() << o.metaObject()->className(); 
} 

#include "main.moc" 
// "main.moc" depends on the declaration of Object above! 

을 위는 SSCCE입니다.

qmake/cmake가 컴파일러에 보내기 전에 moc 출력이 .cpp 파일에 자동으로 추가되도록 빌드를 설정해야한다고 주장 할 수 있습니다. 지금까지는이 기능이 구현되지 않았습니다.