Question

Je souhaite appeler quelques "& static; static " méthodes d'une classe CPP définie dans un fichier différent, mais j'ai des problèmes de liaison. J'ai créé un cas de test qui recrée mon problème et dont le code est ci-dessous.

(Je suis complètement nouveau en C ++, je viens de Java et je connais un peu 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;
                }
        }
}

Lorsque j'ai essayé de compiler, j'obtiens le message d'erreur suivant:

$ 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

Mais si je supprime la déclaration de la classe dans main.cpp et la remplace par #include "CppClass.cpp", cela fonctionne correctement. En gros, je veux mettre ces déclarations dans un fichier .h séparé et l’utiliser. Est-ce que je manque quelque chose?

Merci pour l'aide.

Était-ce utile?

La solution

Il est évident que vous venez d'un environnement Java, car vous n'avez pas encore compris le concept des fichiers d'en-tête. En Java, le processus de définition de quelque chose se fait généralement en un seul morceau. Vous déclarez et définissez en même temps. En C / C ++, il s’agit d’un processus en deux étapes. En déclarant quelque chose qui dit au compilateur "quelque chose existe avec ce type, mais je vous dirai plus tard comment il est réellement implémenté". Définir quelque chose donne au compilateur la partie implémentation réelle. Les fichiers d’en-tête sont principalement utilisés pour les déclarations, les fichiers .cpp pour les définitions.

Les fichiers d’en-tête sont là pour décrire le " API " des classes, mais pas leur code réel. Il est possible d'inclure du code dans l'en-tête, cela s'appelle en-tête. Vous avez tout inséré dans CppClass.cpp (ce n'est pas bien, l'entête-ligne devrait être l'exception), puis vous déclarez votre classe dans main.cpp AGAIN, qui est une double déclaration en C ++. L'inlining dans le corps de la classe entraîne la reduplication du code chaque fois que vous utilisez une méthode (cela ne sembler que ) est fou. Consultez la Section des faq C ++ sur l’alignement pour plus de détails.)

Inclure la double déclaration dans votre code vous donne une erreur de compilation. Laisser le code de classe en dehors de la compilation compile mais vous génère une erreur de l'éditeur de liens, car vous ne disposez plus que de la déclaration de classe de type en-tête dans main.cpp. L'éditeur de liens ne voit aucun code qui implémente vos méthodes de classe, c'est pourquoi les erreurs apparaissent. Contrairement à Java, l’éditeur de liens C ++ NE recherchera PAS automatiquement les fichiers objets qu’il souhaite utiliser. Si vous utilisez la classe XYZ et ne lui donnez pas de code objet pour XYZ, cela échouera simplement.

Veuillez consulter l'article du fichier d'en-tête de Wikipedia et Modèles d’inclusion de fichiers d’en-tête (le lien se trouve également au bas de l’article Wikipedia et contient plus d’exemples)

En bref:

Pour chaque classe, générez un fichier NewClass.h et NewClass.cpp.

Dans le fichier NewClass.h, écrivez:

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

Dans le fichier NewClass.cpp, écrivez:

#include "NewClass.h"

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

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

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

Dans main.cpp, écrivez:

#include "NewClass.h"

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

Pour lier le tout ensemble, effectuez une

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

(juste un exemple avec gcc)

Autres conseils

Vous définissez la classe deux fois, ce qui, j'en suis sûr, ne fonctionne pas.

Essayez quelque chose comme ça:

D'abord un fichier d'en-tête CppClass.h:

// 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();
};

Ensuite, un fichier CppClass.cpp l'implémentant:

// 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 */
}

Ensuite, votre fichier principal:

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

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

Je crois que l'appel g ++ serait le même.

En gros, vous ne pouvez pas déclarer deux fois la même classe. Vous devez déclarer la classe dans le fichier d'en-tête, puis déclarer l'implémentation dans le fichier cpp. Vous pouvez également mettre tout le code en ligne dans une déclaration unique de la classe dans un fichier d'en-tête. Mais le déclarer deux fois comme vous ne le ferez pas.

J'espère que cela a du sens ...

Je pense que vous voulez faire quelque chose comme:

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

Cela devrait résoudre le problème.

créez un fichier .h avec la définition de classe qu'il contient, puis insérez # ce fichier dans vos 2 fichiers.

Bien sûr, l’éditeur de liens ne récupère pas votre deuxième fichier source.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top