Pergunta

Eu quero chamar alguns métodos "estáticos" de uma classe CPP definido em um arquivo diferente, mas eu estou tendo problemas de ligação. Eu criei um caso de teste que recria o meu problema e o código para ele é abaixo.

(eu sou completamente novo para C ++, eu venho de um fundo de Java e estou um pouco familiarizado com 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 eu tentei compilar, eu recebo o seguinte erro:

$ 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

Mas se eu retirar a declaração de classe no main.cpp e substituí-lo por #include "CppClass.cpp", ele funciona bem. Basicamente, eu quero colocar estas declarações em um arquivo .h separado e usá-lo. Estou faltando alguma coisa?

Obrigado pela ajuda.

Foi útil?

Solução

É óbvio que você vem de um fundo Java, porque você ainda não compreenderam o conceito de arquivos de cabeçalho. Em Java o processo de definição algo está geralmente em uma única peça. Você declarar e definir ao mesmo tempo. Em C / C ++ que é um processo de duas etapas. Declarando algo informa o compilador "algo existe com este tipo, mas eu vou te dizer mais tarde como ele é de fato implementado". Definição algo está dando o compilador a parte real implementação. arquivos de cabeçalho são usadas principalmente para declarações, arquivos .cpp para definições.

Os arquivos de cabeçalho estão lá para descrever a "API" de classes, mas não o seu código real. É possível incluir código no cabeçalho, que é chamado de-header inlining. Você inlined tudo em CppClass.cpp (não é bom, header-inlining deve ser a exceção), e então você declarar sua classe em main.cpp novamente, o que é uma declaração dupla em C ++. O inlining nas derivações corpo classe para toda reduplicação código que você usar um método (isto só sons insano. Veja o seção FAQ C ++ em inlining para mais detalhes.)

Incluindo a declaração dupla em seu código lhe dá um erro do compilador. Deixando o código da classe para fora compila mas dá-lhe um erro de vinculador porque agora você só tem o cabeçalho-like declaração de classe no main.cpp. O vinculador vê nenhum código que implementa seus métodos de classe, por isso é que os erros aparecem. Diferente de Java, o vinculador C ++ não irá procurar automaticamente por arquivos objeto que ele quer usar. Se você usar classe XYZ e não dar-lhe opor código para XYZ, ele simplesmente irá falhar.

Por favor, dê uma olhada no artigo arquivo de cabeçalho da Wikipédia e Header Arquivo Incluir padrões (o link está também na parte inferior do artigo Wikipedia e contém mais exemplos)

Em resumo:

Para cada classe, gerar um arquivo NewClass.h e NewClass.cpp.

No arquivo NewClass.h, escreve:

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

No arquivo NewClass.cpp, escreve:

#include "NewClass.h"

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

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

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

Em main.cpp, escreve:

#include "NewClass.h"

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

Para vinculá-lo todos juntos, fazer um

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

(apenas um exemplo com gcc)

Outras dicas

Você está definindo a classe duas vezes, que eu tenho certeza que não funciona.

Tente algo parecido com isto:

Primeiro, um arquivo de cabeçalho 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();
};

Em seguida, um arquivo CppClass.cpp implementá-lo:

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

Em seguida, o arquivo principal:

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

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

Eu acredito que o g chamada ++ seria o mesmo.

Basicamente, você não pode declarar a mesma classe duas vezes. Você deve declarar a classe no arquivo de cabeçalho, em seguida, declarar a implementação no arquivo cpp. Você também pode colocar todo o código embutido em um única declaração da classe em um arquivo de cabeçalho. Mas declará-lo duas vezes como você fez não vai funcionar.

Espero que fazia sentido ...

Eu acho que você quer fazer algo como:

g ++ -c CppClass.cpp g ++ -c Main.cpp g ++ -o ir main.o CppClass.o

Isso deve resolvê-lo.

fazer um arquivo .h com a definição de classe nele, e depois # include o arquivo em seus 2 arquivos.

seguro se parece com o vinculador não está pegando você segundo arquivo de origem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top