Errori di GCC C ++ Linker: riferimento non definito a ‘vtable per XXX’, riferimento non definito a ‘ClassName :: ClassName ()’

Sto configurando un progetto C ++, su Ubuntu x64, usando Eclipse-CDT. Sto fondamentalmente facendo un ciao mondo e collegandomi con una libreria commerciale di terze parti.

Ho incluso i file di intestazione, collegati alle loro librerie, ma ho ancora errori di linker. Ci sono alcuni possibili problemi qui oltre all’ovvio (ad esempio, sono sicuro al 99% che sto collegando alla libreria corretta).

  1. C’è un modo per confermare le librerie statiche che sto collegando a 64 bit?
  2. C’è un modo per confermare che la libreria ha la class (e i metodi) che mi aspetto che abbia?

Eclipse dice:

 Obiettivo di costruzione: LinkProblem
 Invocazione: GCC C ++ Linker
 g ++ -L / home / notroot / spazio di lavoro / somelib-3 / somelib / target / bin -o "LinkProblem" ./src/LinkProblem.o -lsomelib1 -lpthread -lsomelib2 -lsomelib3
 ./src/LinkProblem.o: nella funzione `main ':
 /home/notroot/workspace/LinkProblem/Debug/../src/LinkProblem.cpp:17: riferimento non definito a `SomeClass :: close () '
 ./src/LinkProblem.o: nella funzione `SomeOtherClass ':
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:148: riferimento non definito a `SomeClass :: SomeClass () '
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:148: riferimento non definito a `vtable per SomeOtherClass '
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:151: riferimento non definito a `SomeClass :: ~ SomeClass () '
 ./src/LinkProblem.o: nella funzione `~ SomeOtherClass ':
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: riferimento non definito a `vtable per SomeOtherClass '
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: riferimento non definito a `SomeClass :: ~ SomeClass () '
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: riferimento non definito a `SomeClass :: ~ SomeClass () '
 collect2: ld ha restituito 1 stato di uscita
 make: *** [LinkProblem] Errore 1

Supponendo che quei metodi siano in una delle librerie sembra un problema di ordinamento.

Quando si collegano le librerie in un eseguibile, vengono eseguite nell’ordine in cui sono dichiarate.
Anche il linker prenderà solo i metodi / le funzioni necessarie per risolvere le dipendenze attualmente in sospeso. Se una libreria successiva utilizza quindi metodi / funzioni che non erano originariamente richiesti dagli oggetti, si avranno delle dipendenze mancanti.

Come funziona:

  • Prendi tutti i file object e combinali in un eseguibile
  • Risolvi eventuali dipendenze tra i file object.
  • Per ogni libreria in ordine:
    • Controlla le dipendenze irrisolte e verifica se la lib le risolve.
    • Se così si carica parte necessaria nell’eseguibile.

Esempio:

Gli oggetti richiedono:

  • Aperto
  • Vicino
  • BatchRead
  • BatchWrite

Lib 1 fornisce:

  • Aperto
  • Vicino
  • leggere
  • Scrivi

Lib 2 fornisce

  • BatchRead (ma usa lib1: leggi)
  • BatchWrite (ma usa lib1: write)

Se collegato in questo modo:

gcc -o plop.o -l1 -l2

Quindi il linker non riuscirà a risolvere i simboli di lettura e scrittura.

Ma se collego l’applicazione in questo modo:

gcc -o plop.o -l2 -l1

Quindi collegherà correttamente. Come l2 risolve le dipendenze di BatchRead e BatchWrite ma aggiunge anche due nuove (leggi e scrivi). Quando ci colleghiamo a l1, vengono risolte tutte e quattro le dipendenze.

Solitamente questo errore del linker (nella mia esperienza) significa che hai sovrascritto una funzione virtuale in una class figlia con una dichiarazione, ma non hai dato una definizione per il metodo. Per esempio:

class Base { virtual void f() = 0; } class Derived : public Base { void f(); } 

Ma non hai dato la definizione di f. Quando si utilizza la class, si ottiene l’errore del linker. Proprio come un normale errore del linker, è perché il compilatore sapeva di cosa stavi parlando, ma il linker non riusciva a trovare la definizione. Ha appena ricevuto un messaggio molto difficile da capire.

Qt C ++ mostrerà questo errore quando cambi una class in modo che ora erediti da QObject (cioè in modo che ora possa usare segnali / slot). L’esecuzione di qmake -r chiamerà moc e risolverà questo problema.

Se stai lavorando con gli altri tramite una sorta di controllo di versione, vorrai apportare qualche modifica al tuo file .pro (ad esempio aggiungi / rimuovi una riga vuota). Quando tutti gli altri ricevono le modifiche e le esecuzioni vengono eseguite, make vedrà che il file .pro è stato modificato ed esegue automaticamente qmake. Questo salverà i tuoi compagni di squadra dal ripetere la tua frustrazione.

Il problema per me si è rivelato piuttosto oscuro. La mia class sembrava così:

 //----------------------------------------- // libbase.h class base { public: base() { } virtual ~base() { } virtual int foo() { return 0; } }; //----------------------------------------- //----------------------------------------- // libbase.cpp #include "libbase.h" //----------------------------------------- //----------------------------------------- // main.h class derived : public base { public: virtual int foo() ; }; //----------------------------------------- //----------------------------------------- // main.cpp int main () { derived d; } //----------------------------------------- 

Il problema è nel linker. Il mio file di intestazione è andato in una libreria da qualche parte, ma tutte le funzioni virtuali sono state dichiarate “in linea” nella dichiarazione della class. Poiché non esisteva un codice che utilizzava le funzioni virtuali (ancora), il compilatore o il linker trascuravano di mettere in atto i corpi delle funzioni reali. Inoltre non è riuscito a creare il vtable.

Nel mio codice principale in cui sono derivato da questa class, il linker ha provato a colbind la mia class alla class base e al suo vtable. Ma il vtable era stato scartato.

La soluzione era dichiarare almeno uno dei corpi delle funzioni virtuali al di fuori della dichiarazione di class, in questo modo:

 //----------------------------------------- // libbase.h class base { public: base() { } virtual ~base() ; //-- No longer declared 'inline' virtual int foo() { return 0; } }; //----------------------------------------- //----------------------------------------- // libbase.cpp #include "libbase.h" base::~base() { } //----------------------------------------- 

Per quanto riguarda i problemi con Qt4, non ho potuto usare l’opzione qmake moc menzionata sopra. Ma non era questo il problema comunque. Ho avuto il seguente codice nella definizione della class:

 class ScreenWidget : public QGLWidget { Q_OBJECT // must include this if you use Qt signals/slots ... }; 

Ho dovuto rimuovere la linea “Q_OBJECT” perché non avevo segnali o slot definiti.

Ho avuto questo messaggio di errore. Il problema era che ho dichiarato un distruttore virtuale nel file di intestazione, ma il corpo delle funzioni virtuali non è stato effettivamente implementato.

Questo errore si verifica anche quando dichiariamo semplicemente una funzione virtuale senza alcuna definizione nella class base.

Per esempio:

 class Base { virtual void method1(); // throws undefined reference error. } 

Cambia la dichiarazione di cui sopra in quella sottostante, funzionerà bene.

 class Base { virtual void method1() { } } 

Nel mio caso il problema si è verificato quando ho dimenticato di aggiungere il = 0 su una funzione nella mia pura class virtuale. È stato corretto quando è stato aggiunto il valore = 0. Lo stesso di Frank sopra.

 class ISettings { public: virtual ~ISettings() {}; virtual void OKFunction() =0; virtual void ProblemFunction(); // missing =0 }; class Settings : ISettings { virtual ~Settings() {}; void OKFunction(); void ProblemFunction(); }; void Settings::OKFunction() { //stuff } void Settings::ProblemFunction() { //stuff } 

Ora sono incappato anche nel problema. L’applicazione definiva una pura class di interfaccia virtuale e una class definita dall’utente fornita attraverso una lib condivisa doveva implementare l’interfaccia. Durante il collegamento dell’applicazione, il linker si è lamentato del fatto che la lib condivisa non avrebbe fornito vtable e type_info per la class base, né potrebbero essere trovati da nessun’altra parte. Ho scoperto che ho semplicemente dimenticato di rendere virtuale uno dei metodi dell’interfaccia (ovvero omesso il “= 0” alla fine della dichiarazione. Molto rudimentale, ancora facile da trascurare e sconcertante se non riesci a connettere la diagnostica del linker al causa ultima.

Ho avuto questo messaggio di errore quando provavo “ciao mondo” come cose con Qt. I problemi sono stati risolti eseguendo correttamente qt moc (meta object compiler) e compilando + inclusi correttamente questi file generati da moc.

Se hai una class base con pura funzione virtuale, assicurati che il costruttore e il distruttore della class base abbia corpo altrimenti il ​​linker fallisce.

Lo metto per i futuri visitatori:

se si riceve l’errore durante la creazione di un object Exception , la causa di ciò è probabilmente la mancanza di definizione della funzione virtuale what() .