Domanda

Voglio chiamare alcuni "statici" metodi di una classe CPP definiti in un file diverso ma sto riscontrando problemi di collegamento. Ho creato un caso di prova che ricrea il mio problema e il codice è riportato di seguito.

(Sono completamente nuovo in C ++, vengo da un background Java e ho un po 'di familiarità con C.)

// CppClass.cpp
#include <iostream>
#include <pthread.h>

static pthread_t thread;
static pthread_mutex_t mutex;
static pthread_cond_t cond;
static int shutdown;

using namespace std;

class CppClass
{
public:
        static void Start()
        {
                cout << "Testing start function." << endl;
                shutdown = 0;
                pthread_attr_t attr;
                pthread_attr_init(&attr);
                pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
                pthread_mutex_init(&mutex, NULL);
                pthread_cond_init(&cond, NULL);

                pthread_create(&thread, &attr, run_thread, NULL);
        }

        static void Stop()
        {
                pthread_mutex_lock(&mutex);
                shutdown = 1;
                pthread_cond_broadcast(&cond);
                pthread_mutex_unlock(&mutex);
        }

        static void Join()
        {
                pthread_join(thread, NULL);
        }
private:
        static void *run_thread(void *pthread_args)
        {
                CppClass *obj = new CppClass();
                pthread_mutex_lock(&mutex);
                while (shutdown == 0)
                {
                        struct timespec ts;
                        ts.tv_sec = time(NULL) + 3;
                        pthread_cond_timedwait(&cond, &mutex, &ts);
                        if (shutdown)
                        {
                                break;
                        }
                        obj->display();
                }
                pthread_mutex_unlock(&mutex);
                pthread_mutex_destroy(&mutex);
                pthread_cond_destroy(&cond);
                pthread_exit(NULL);
                return NULL;
        }

        void display()
        {
                cout << " Inside display() " << endl;
        }
};

// main.cpp
#include <iostream>
/* 
 * If I remove the comment below and delete the
 * the class declaration part, it works.
 */
// #include "CppClass.cpp"
using namespace std;

class CppClass
{
public:
        static void Start();
        static void Stop();
        static void Join();
};

int main()
{
        CppClass::Start();
        while (1)
        {
                int quit;
                cout << "Do you want to end?: (0 = stay, 1 = quit) ";
                cin >> quit;
                cout << "Input: " << quit << endl;
                if (quit)
                {
                        CppClass::Stop();
                        cout << "Joining CppClass..." << endl;
                        CppClass::Join();
                        break;
                }
        }
}

Quando ho provato a compilare, ho visualizzato il seguente errore:

$ g++ -o go main.cpp CppClass.cpp -l pthread
/tmp/cclhBttM.o(.text+0x119): In function `main':
: undefined reference to `CppClass::Start()'
/tmp/cclhBttM.o(.text+0x182): In function `main':
: undefined reference to `CppClass::Stop()'
/tmp/cclhBttM.o(.text+0x1ad): In function `main':
: undefined reference to `CppClass::Join()'
collect2: ld returned 1 exit status

Ma se rimuovo la dichiarazione di classe in main.cpp e la sostituisco con #include " CppClass.cpp " ;, funziona benissimo. Fondamentalmente, voglio mettere queste dichiarazioni in un file .h separato e usarlo. Mi sto perdendo qualcosa?

Grazie per l'aiuto.

È stato utile?

Soluzione

È ovvio che provieni da un background Java perché non hai ancora capito il concetto di file header. In Java il processo di definizione di qualcosa è di solito in un unico pezzo. Dichiarate e definite allo stesso tempo. In C / C ++ è un processo in due fasi. Dichiarazione qualcosa dice al compilatore " qualcosa esiste con questo tipo, ma ti dirò in seguito come viene effettivamente implementata " ;. Definire qualcosa sta dando al compilatore la parte di implementazione effettiva. I file di intestazione vengono utilizzati principalmente per le dichiarazioni, i file .cpp per le definizioni.

I file di intestazione sono lì per descrivere l'API " di classi, ma non il loro codice reale. È possibile includere il codice nell'intestazione, che si chiama intestazione-inlining. Hai inserito tutto in CppClass.cpp (non va bene, l'header inlining dovrebbe essere l'eccezione), e poi dichiari nuovamente la tua classe in main.cpp che è una doppia dichiarazione in C ++. L'allineamento nel corpo della classe porta alla riduplicazione del codice ogni volta che usi un metodo (solo suona folle. Vedi sezione faq C ++ sull'inline per dettagli.)

Includere la doppia dichiarazione nel tuo codice ti dà un errore del compilatore. Lasciare il codice della classe fuori compilato ma ti dà un errore del linker perché ora hai solo la dichiarazione di classe simile all'intestazione in main.cpp. Il linker non vede alcun codice che implementa i metodi della tua classe, ecco perché compaiono gli errori. Diversamente da Java, il linker C ++ NON cercherà automaticamente i file oggetto che desidera utilizzare. Se usi la classe XYZ e non gli dai il codice oggetto per XYZ, fallirà semplicemente.

Dai un'occhiata a articolo del file di intestazione di Wikipedia e File di intestazione Includi pattern (il collegamento è anche in fondo all'articolo di Wikipedia e contiene più esempi)

In breve:

Per ogni classe, genera un file NewClass.h e NewClass.cpp.

Nel file NewClass.h, scrivi:

class NewClass {
public:
   NewClass();
   int methodA();
   int methodB();
}; <- don't forget the semicolon

Nel file NewClass.cpp, scrivi:

#include "NewClass.h"

NewClass::NewClass() {
  // constructor goes here
}

int NewClass::methodA() {
  // methodA goes here
  return 0;
}

int NewClass::methodB() {
  // methodB goes here
  return 1;
}

In main.cpp, scrivi:

#include "NewClass.h"

int main() {
  NewClass nc;
  // do something with nc
}

Per collegare tutto insieme, fai un

g ++ -o NewClassExe NewClass.cpp main.cpp

(solo un esempio con gcc)

Altri suggerimenti

Stai definendo la classe due volte, che sono sicuro che non funziona.

Prova qualcosa del genere:

Prima un file CppClass.h di intestazione:

// CppClass.h
using namespace std;

class CppClass
{
public:
    static void Start();
    static void Stop();
    static void Join();
private:
    void *run_thread(void *pthread_args);
    void display();
};

Quindi un file CppClass.cpp che lo implementa:

// CppClass.cpp
#include <iostream>
#include <pthread.h>
#include "CppClass.h"

using namespace std;

void CppClass::Start()
{
    /* method body goes here */
}
void CppClass::Stop()
{
    /* method body goes here */
}
void CppClass::Join()
{
    /* method body goes here */
}
void *CppClass::run_thread(void *pthread_args)
{
    /* method body goes here */
}
void CppClass::display() {
    /* method body goes here */
}

Quindi il tuo file principale:

// main.cpp
#include "CppClass.h"

int main()
{
    /* main method body here */
}

Credo che la chiamata g ++ sia la stessa.

Fondamentalmente, non puoi dichiarare la stessa classe due volte. È necessario dichiarare la classe nel file di intestazione, quindi dichiarare l'implementazione nel file cpp. Puoi anche inserire tutto il codice in linea in una singola dichiarazione della classe in un file di intestazione. Ma dichiararlo due volte come hai fatto non funzionerà.

Spero che abbia senso ...

Penso che tu voglia fare qualcosa del tipo:

g ++ -c CppClass.cpp g ++ -c main.cpp g ++ -o vai main.o CppClass.o

Questo dovrebbe risolverlo.

crea un file .h con la definizione della classe, quindi #include quel file nei tuoi 2 file.

Sembra che il linker non stia raccogliendo il tuo secondo file sorgente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top