2010-03-31 11 views
51

यह मेरा शीर्षक है: क्यूटी लिंकर त्रुटि: "अपरिभाषित संदर्भ vtable करने के लिए"

#ifndef BARELYSOCKET_H 
#define BARELYSOCKET_H 

#include <QObject> 
//! The First Draw of the BarelySocket! 

class BarelySocket: public QObject 
{ 
    Q_OBJECT 

public: 
    BarelySocket(); 
public slots: 
    void sendMessage(Message aMessage); 
signals: 
    void reciveMessage(Message aMessage); 

private: 
    // QVector<Message> reciveMessages; 
}; 

#endif // BARELYSOCKET_H 

यह मेरी कक्षा है:

undefined reference to 'vtable for BarelySocket' 
:

#include <QTGui> 
#include <QObject> 
#include "type.h" 
#include "client.h" 
#include "server.h" 

#include "barelysocket.h" 

BarelySocket::BarelySocket() 
{ 
    //this->reciveMessages.clear(); 
    qDebug("BarelySocket::BarelySocket()"); 
} 

void BarelySocket::sendMessage(Message aMessage) 
{ 
} 

void BarelySocket::reciveMessage(Message aMessage) 
{ 
} 

मैं एक लिंकर त्रुटि मिलती है

  • इसका तात्पर्य है कि मेरे पास वर्चुअल विधि लागू नहीं है। लेकिन वहां मेरी कक्षा में कोई वर्चुअल विधियां नहीं हैं।
  • मैंने वेक्टर को यह सोचकर टिप्पणी की कि यह कारण था, लेकिन त्रुटि दूर नहीं गई।
  • Message एक जटिल struct है, लेकिन int का उपयोग करने के बजाय चीजों को ठीक नहीं करता है।
+7

क्या आपने 'qmake' चलाने से शुरू होने वाले क्लीन बिल्ड की कोशिश की है? ऐसा तब हो सकता है जब 'moc' किसी कारण से आपकी कक्षा के लिए शीर्षलेख को संसाधित नहीं करता है। –

+0

मैं क्यूटी निर्माता के साथ काम कर रहा हूं। मैंने सभी सीपीपी फ़ाइलों को एक नए स्वच्छ प्रोजेक्ट में कॉपी किया। मैंने स्लॉट कार्यान्वयन को हटा दिया है जिसे मैंने कोडित किया है। जहां समस्याएं आई थीं। आपकी मदद के लिए धन्यवाद! – Thomas

उत्तर

10

अनुभव से: अक्सर एक qmake & & स्वच्छ & & बनाने में मदद करता हैं। मैं व्यक्तिगत रूप से समझता हूं कि कभी-कभी परिवर्तन की खोज/कैशिंग प्रभाव/जो कुछ भी मैं नहीं जानता हूं XXXXX। मैं यह नहीं कह सकता क्यों, लेकिन जब मैं इस तरह की गलती का सामना करता हूं तो यह पहली बात है।

बीटीडब्ल्यू। वहाँ एक टाइपो है> <

आप अपने कन्स्ट्रक्टर (प्रारंभकर्ता सूची में) में QObject कन्स्ट्रक्टर को कॉल करना भूल गए हैं। (हालांकि यह त्रुटि को हल नहीं करता है)

+5

यह विशेष रूप से उपयोगी है जब फ़ाइल मौजूद है लेकिन qmake चलाए जाने पर इसमें कोई Q_OBJECT संदर्भ नहीं था।qmake तब विश्वास नहीं करता है कि इसे moc चलाने की आवश्यकता है और आप vtable त्रुटियों के साथ समाप्त होता है। मेक क्लीन हमेशा जरूरी नहीं है, लेकिन जब कुछ संरचनात्मक परिवर्तन किए जाते हैं। –

+4

यह भी सुनिश्चित करें कि barelyocket.h आपकी प्रो फ़ाइल में हेडर अनुभाग में है। – chalup

2

सिग्नल में कार्यान्वयन नहीं होना चाहिए (यह क्यूटी द्वारा उत्पन्न किया जाएगा)। अपनी .cpp फ़ाइल से reciveMessage कार्यान्वयन को हटाएं। यह आपकी समस्या का समाधान कर सकता है।

एक और चीज जो मैंने देखी है: चूंकि BarelySocket वर्ग QObject से प्राप्त होता है, इसके विनाश के दौरान समस्या से बचने के लिए एक आभासी विनाशक होना चाहिए। यह सभी वर्गों के लिए किया जाना चाहिए जो किसी अन्य वर्ग से प्राप्त होते हैं।

+0

प्राप्त करना मैसेज कार्यान्वयन आवश्यक है, लेकिन यह "परिभाषित प्रतीक गुणा" त्रुटि का कारण बन जाएगा। यदि आधार वर्ग (इस मामले में QObject) में वर्चुअल विनाशक है, तो सभी व्युत्पन्न कक्षाओं में विनाशक स्वचालित रूप से आभासी होते हैं। तो यह यहाँ कोई मुद्दा नहीं है। – chalup

12

मैं इस त्रुटि में भाग गया जब मैंने एक छोटी सी "main.cpp" फ़ाइल के अंदर एक छोटी कक्षा बनाई, जिसे मैंने कुछ परीक्षण करने के लिए बनाया था।

एक घंटे या उससे भी अधिक समय के लिए futzing के बाद, मैं अंत में उस वर्ग को main.cpp से बाहर ले गया और एक स्टैंडअलोन एचपीपी फ़ाइल में चला गया, .pro (प्रोजेक्ट) फ़ाइल अद्यतन किया और परियोजना फिर पूरी तरह से ठीक बनाया गया। हो सकता है कि यह मुद्दा यहां न हो लेकिन मुझे लगा कि यह उपयोगी जानकारी होगी।

+0

मैंने आज भी वही गलती की है! एक घंटे या तो भी खो गया ... –

109

जब भी आप Q_OBJECT मैक्रो में कोई नया कॉल जोड़ते हैं, तो आपको फिर से qmake चलाने की आवश्यकता होती है। जिस vtables समस्या का आप जिक्र कर रहे हैं वह उससे सीधे संबंधित है।

बस qmake चलाएं और आपको यह मानने के लिए अच्छा होना चाहिए कि आपके कोड में कोई अन्य समस्या नहीं है।

+16

QT निर्माता के भीतर बिल्ड मेनू से रन qmake का उपयोग करें। –

+0

धन्यवाद! कमांड लाइन से, केवल 'मेक' का उपयोग करके कुछ क्यूमेक से संबंधित सामान भी अपडेट होते हैं, लेकिन स्पष्ट रूप से पर्याप्त नहीं है। जाहिर है, 'qmake' चल रहा है, वास्तव में, आवश्यक है। – Thomas

+0

qmake चलाना मेरे लिए पर्याप्त नहीं है, मुझे अपने बिल्ड फ़ोल्डर को फिर से कंपाइल करना था। – PaulrBear

2

जब आप QOBject (और Q_OBJECT मैक्रो का उपयोग करें) से कक्षा प्राप्त करते हैं, तो विशेष रूप से निर्माता और विनाशक वर्ग दोनों को परिभाषित और बनाने के लिए मत भूलना। यह कंपाइलर डिफ़ॉल्ट कन्स्ट्रक्टर/विनाशकों का उपयोग करने के लिए पर्याप्त नहीं है। Qmake की सफाई/चलने (और आपकी moc_ फ़ाइलों को साफ़ करने) पर सलाह अभी भी लागू होती है। यह मेरी इसी तरह की समस्या तय करता है।

3

मेरे लिए, मैंने बिल्ड लॉग से देखा जो मोक नहीं कहा गया था।स्वच्छ सभी मदद नहीं की। तो मैंने .pro.user को हटा दिया, आईडीई को पुनरारंभ किया और यह चाल चल गई।

26

मैंने समस्या को हल करने के कई तरीके देखे हैं, लेकिन ऐसा क्यों नहीं होता है इसके लिए कोई स्पष्टीकरण नहीं है, इसलिए यहां जाता है।

जब संकलक वर्चुअल फ़ंक्शंस (सीधे घोषित या विरासत में) के साथ कक्षा देखता है, तो उसे उस वर्ग के लिए एक vtable उत्पन्न करना होगा। चूंकि वर्गों को आमतौर पर शीर्षकों में परिभाषित किया जाता है (और इस प्रकार एकाधिक अनुवाद इकाइयों में दिखाई देता है), प्रश्न यह है कि vtable को कहां रखा जाए।

सामान्य रूप से, समस्या को प्रत्येक टीयू में vtable उत्पन्न करके हल किया जा सकता है जहां कक्षा परिभाषित की जाती है, और फिर लिंकर डुप्लीकेट को खत्म करने दें। चूंकि कक्षा परिभाषाओं को ओडीआर द्वारा हर घटना पर समान होना आवश्यक है, यह सुरक्षित है। हालांकि, यह संकलन धीमा कर देता है, ऑब्जेक्ट फाइलों को ब्लोट करता है, और लिंकर को और अधिक काम करने की आवश्यकता होती है।

एक अनुकूलन के रूप में, इसलिए, compilers, जब संभव हो, एक विशिष्ट टीयू में vtable डाल करने के लिए चयन करेंगे। आम सी ++ ABI में, इस टीयू एक जहाँ वर्ग के कुंजी समारोह में कार्यान्वित किया जाता है, जहां कुंजी फ़ंक्शन प्रथम वर्चुअल सदस्य फ़ंक्शन है जिसे कक्षा में घोषित किया गया है, लेकिन परिभाषित नहीं किया गया है।

क्यूटी कक्षाओं के मामले में, वे आम तौर पर Q_OBJECT मैक्रो के साथ शुरू, और इस मैक्रो घोषणा-पत्र शामिल

virtual const QMetaObject *metaObject() const; 

जो है, क्योंकि यह मैक्रो में पहली आभासी समारोह है, आम तौर पर पहले हो जाएगा कक्षा का वर्चुअल फ़ंक्शन और इस प्रकार इसका मुख्य कार्य। इसलिए संकलक अधिकांश टीयू में vtable को उत्सर्जित नहीं करेगा, केवल metaObject लागू करता है। और जब यह हेडर को संसाधित करता है तो इस फ़ंक्शन का कार्यान्वयन moc द्वारा स्वचालित रूप से लिखा जाता है। इस प्रकार, आपको moc एक नई .cpp फ़ाइल जेनरेट करने के लिए अपने शीर्षलेख को संसाधित करने की आवश्यकता है, और फिर अपने संकलन में .cpp फ़ाइल शामिल करें।

तो आप एक नया हैडर कि एक QObject व्युत्पन्न वर्ग को परिभाषित करता हो तब आप qmake को फिर से चलाएं, ताकि वह अपने makefiles अद्यतन करता है नई हैडर पर moc चलाने के लिए और जिसके परिणामस्वरूप .cpp फ़ाइल को संकलित करने की जरूरत है।

+6

बहुत बढ़िया लेखन-अप। मैं qmake के बजाय सीएमके का उपयोग कर रहा हूं, और मुझे यह त्रुटि बहुत बार दिखाई देती है; बुनियादी सी ++ vtable जानकारी को समझना बहुत निराशाजनक है और अभी भी यह पता लगाने में सक्षम नहीं है कि क्या गलत हो रहा है। धन्यवाद! –

+0

@ केली स्ट्रैंड को सेट नहीं करना चाहिए (CMAKE_AUTOMOC चालू) पर्याप्त होना चाहिए? मेरे पास एक क्यूटी लाइब्रेरी है और मुझे vtable त्रुटि से बचने के लिए हर बार 'qmake' चलाने की ज़रूरत है। क्या इसका मतलब है 'cmake'' moc' नहीं चल रहा है जैसा कि इसे करना चाहिए? –

+1

@ जेम्स हिर्शोर्न आप सोचेंगे कि पर्याप्त होना चाहिए, हां। और वास्तव में यह * प्रकट होता है कि इनपुट फ़ाइलों को वास्तव में बदल दिया गया है या नहीं, इसके बिना हर निर्माण के लिए 'moc' फिर से चलाया जाता है। मुझे सच में यकीन नहीं है कि मौलिक सीएमके समस्या क्या है। –

0

मुझे एक और कारण मिला है कि आप इसे क्यों देख सकते हैं - qmake आपकी कक्षा फ़ाइलों के माध्यम से पार्स करते हैं यदि आपने उन्हें गैर-मानक तरीके से संशोधित किया है तो आपको यह त्रुटि मिल सकती है। मेरे मामले में मेरे पास एक कस्टम संवाद था जो QDialog से विरासत में मिला था, लेकिन मैं केवल चाहता था कि लिनक्स के निर्माण के दौरान संकलित और चलाएं, विंडोज या ओएसएक्स नहीं। मैं बस #ifdef __linux__ कक्षा को बाहर कर रहा था, इसलिए यह संकलित नहीं हुआ था, लेकिन लिनक्स में __linux__ को परिभाषित किया गया था कि यह qmake को फेंक रहा था।

1

मैंने इस त्रुटि घंटों के साथ संघर्ष किया। एक अलग फ़ोल्डर (।) में .cpp और .h फ़ाइल डालकर इसे हल करें। फिर .pro फ़ाइल में फ़ोल्डर कहा: INCLUDEPATH + = $$ {_ PRO_FILE_PWD _} /../ MyClasses/CMyClassWidget

और उसके बाद सीपीपी और ज फ़ाइल जोड़ा। आखिरकार काम करता है।

संबंधित मुद्दे