我想调用在不同文件中定义的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文件中并使用它。我错过了什么吗?
感谢您的帮助。
答案 0 :(得分:32)
很明显,你来自Java背景,因为你还没有掌握头文件的概念。在Java中,定义某事的过程通常是一个整体。您同时声明和定义。在C / C ++中,这是一个两步过程。 声明某事告诉编译器“这种类型存在某种东西,但我稍后会告诉你它是如何实际实现的”。 定义的东西给编译器提供了实际的实现部分。头文件主要用于声明,.cpp文件用于定义。
头文件用于描述类的“API”,但不是它们的实际代码。可以在头文件中包含代码,称为头内联。你已经在CppClass.cpp中内联了所有内容(不好,标题内联应该是例外),然后在main.cpp AGAIN中声明你的类,这是C ++中的双重声明。每次使用方法时,类体中的内联都会导致代码重复(这只是声音疯狂。有关详细信息,请参阅C++ faq section on inlining。)
在代码中包含双重声明会给您带来编译错误。保留类代码编译但会给你一个链接器错误,因为现在你只在main.cpp中有类似头的类声明。链接器看不到实现类方法的代码,这就是错误出现的原因。与Java不同,C ++链接器不会自动搜索它想要使用的目标文件。如果您使用XYZ类并且不为XYZ提供目标代码,那么它将失败。
请查看Wikipedia's header file article和Header File Include Patterns(该链接也位于维基百科文章的底部,包含更多示例)
简而言之:
对于每个类,生成一个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的一个例子)
答案 1 :(得分:9)
你要两次定义课程,我很确定这不起作用。
尝试这样的事情:
首先是标题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文件中声明该实现。您还可以将所有代码内联到头文件中的类的单声明中。但是像你那样宣布它两次是行不通的。
我希望这是有道理的......
答案 2 :(得分:2)
我想你想做点什么:
g ++ -c CppClass.cpp g ++ -c main.cpp g ++ -o go main.o CppClass.o
那应该解决它。
答案 3 :(得分:1)
制作一个带有类定义的.h文件,然后将该文件#include到你的2个文件中。
答案 4 :(得分:0)
当然看起来链接器没有拿起你的第二个源文件。