質問

別のファイルで定義された 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): 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

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

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

役に立ちましたか?

解決

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

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

コードに二重宣言を含めると、コンパイラ エラーが発生します。クラス コードを省略すると、コンパイルは実行されますが、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 を使用した例にすぎません)

他のヒント

クラスを 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 回宣言しても機能しません。

それが理にかなっていればいいのですが...

次のようなことをしたいと思います:

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

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

クラス定義を含む .h ファイルを作成し、そのファイルを 2 つのファイルに #include します。

確かに、リンカーが 2 番目のソース ファイルを選択していないようです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top