8

別のファイルで定義されたCPPクラスのいくつかの「静的」メソッドを呼び出したいのですが、リンクに問題があります。問題を再現するテストケースを作成しました。そのコードは次のとおりです。

(私はC ++に完全に慣れていません。私は、Javaのバックグラウンドを持っており、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;
                }
        }
}

コンパイルしようとすると、次のエラーが発生します。

$ g ++ -o go main.cpp CppClass.cpp -l pthread
/tmp/cclhBttM.o(.text+0x119):関数 `main'内:
:`CppClass :: Start()'への未定義の参照
/tmp/cclhBttM.o(.text+0x182):関数 `main'内:
:`CppClass :: Stop()'への未定義の参照
/tmp/cclhBttM.o(.text+0x1ad):関数 `main'内:
:`CppClass :: Join()'への未定義の参照
collect2:ldが1つの終了ステータスを返しました

しかし、main.cppのクラス宣言を削除し、それを#include "CppClass.cpp"に置き換えると、正常に機能します。基本的に、これらの宣言を別の.hファイルに入れて使用したいと思います。私は何かが足りないのですか?

助けてくれてありがとう。

4

5 に答える 5

33

ヘッダー ファイルの概念をまだ理解していないため、Java のバックグラウンドを持っていることは明らかです。Java では、何かを定義するプロセスは通常 1 つの部分です。宣言と定義を同時に行います。C/C++ では、2 段階のプロセスです。何かを宣言すると、コンパイラに「この型には何かが存在しますが、実際にどのように実装されているかは後で説明します」と通知されます。何かを定義することは、コンパイラに実際の実装部分を与えることです。ヘッダー ファイルは主に宣言に使用され、.cpp ファイルは定義に使用されます。

ヘッダー ファイルは、クラスの「API」を記述するためにありますが、実際のコードではありません。ヘッダーのインライン化と呼ばれるコードをヘッダーに含めることができます。CppClass.cpp ですべてをインライン化して (良くない、ヘッダーのインライン化は例外である必要があります)、main.cpp AGAIN でクラスを宣言します。これは C++ の二重宣言です。クラス本体のインライン化は、メソッドを使用するたびにコードの重複につながります (これは非常識に聞こえるだけです。詳細については、インライン化に関する C++ FAQ セクションを参照してください)。

コードに double 宣言を含めると、コンパイラ エラーが発生します。クラス コードを除外すると、コンパイルは実行されますが、main.cpp にはヘッダーのようなクラス宣言しかないため、リンカー エラーが発生します。リンカーは、クラス メソッドを実装するコードを認識しないため、エラーが表示されます。Java とは異なり、C++ リンカーは、使用するオブジェクト ファイルを自動的に検索しません。クラス XYZ を使用し、XYZ のオブジェクト コードを指定しないと、単純に失敗します。

ウィキペディアのヘッダー ファイルの記事ヘッダー ファイル インクルード パターンをご覧ください(リンクはウィキペディアの記事の下部にもあり、より多くの例が含まれています)。

要するに:

クラスごとに、NewClass.h および NewClass.cpp ファイルを生成します。

NewClass.h ファイルに次のように記述します。

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

NewClass.cpp ファイルに次のように記述します。

#include "NewClass.h"

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

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

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

main.cpp に次のように記述します。

#include "NewClass.h"

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

すべてをリンクするには、

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

(gcc の例)

于 2008-09-22T18:51:39.710 に答える
10

クラスを2回定義していますが、これは機能しないと確信しています。

次のようなものを試してください。

最初にヘッダー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();
};

次に、それを実装するCppClass.cppファイル:

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

次に、メインファイル:

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

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

g++の呼び出しも同じだと思います。

基本的に、同じクラスを2回宣言することはできません。ヘッダーファイルでクラスを宣言してから、cppファイルで実装を宣言する必要があります。ヘッダーファイルのクラスの単一の宣言にすべてのコードをインラインで配置することもできます。しかし、あなたがしたようにそれを2回宣言することはうまくいきません。

私はそれが理にかなっていることを願っています...

于 2008-09-22T19:16:00.510 に答える
2

私はあなたが次のようなことをしたいと思います:

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

それはそれを解決するはずです。

于 2008-09-22T18:45:29.897 に答える
1

make a .h file with the class definition in it, and then #include that file into your 2 files.

于 2008-09-22T18:48:47.797 に答える
0

リンカーが 2 番目のソース ファイルを取得していないようです。

于 2008-09-22T18:51:28.587 に答える