在C ++中链接"静态"方法时出现问题
我想调用在不同文件中定义的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文件中并使用它。我想念什么吗?
谢谢帮助。
解决方案
我认为我们想执行以下操作:
g ++ -c CppClass.cpp
g ++ -c main.cpp
g ++ -o go main.o CppClass.o
那应该解决它。
制作一个带有类定义的.h文件,然后将该文件#include到2个文件中。
可以肯定的是,链接器未启动第二个源文件。
很明显,我们来自Java背景,因为我们尚未掌握头文件的概念。在Java中,定义某些东西的过程通常是一件事情。我们可以同时声明和定义。在C / C ++中,这是一个两步过程。声明某些内容将告诉编译器"此类型存在某些内容,但稍后将告诉我们如何实际实现"。定义一些东西就是给编译器实际的实现部分。头文件主要用于声明,.cpp文件用于定义。
头文件用于描述类的" API",而不是其实际代码。可以在标头中包含称为标头内联的代码。我们已经内联了CppClass.cpp中的所有内容(不好,标头内联应该是例外),然后在main.cpp AGAIN中声明了类,这是C ++中的双重声明。每次使用方法时,类主体中的内联都会导致代码重复(这听起来很疯狂。有关内联的详细信息,请参见C ++常见问题解答部分。)
在代码中包含double声明会给我们带来编译器错误。省略类代码可以编译,但是会给我们一个链接器错误,因为现在在main.cpp中只有类头的类声明。链接器看不到实现类方法的代码,这就是出现错误的原因。与Java不同,C ++链接器不会自动搜索要使用的目标文件。如果我们使用类XYZ而不给它提供XYZ的目标代码,则它只会失败。
请查看Wikipedia的头文件文章和Header File Include Patterns(该链接也位于Wikipedia文章的底部,并且包含更多示例)
简而言之:
对于每个类,生成一个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为例)
我们要两次定义该类,我敢肯定这是行不通的。
尝试这样的事情:
首先是一个头文件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 ++调用将是相同的。
基本上,我们不能两次声明相同的类。我们应该在头文件中声明该类,然后在cpp文件中声明实现。我们还可以将所有代码内联在头文件的类的单个声明中。但是像我们一样两次声明它是行不通的。
我希望这是有道理的...