c++动态库链接错误
声明一个父类Parent,两个子类Son和Daughter继承之,分别将两个子类的创建和实现编译成动态链接库son.so, daughter.so,再通过动态库调用的hello方法:
/* parent.h */
class Parent
{
public:
virtual void hello(void)=0;
virtual void bye(void);
};
/* son.h */
#include "parent.h"
class Son : public Parent
{
virtual void hello(void);
};
extern "C" static Parent* createPeople(void);
/* son.cpp */
#include <stdio.h>
#include "son.h"
void Son::hello(void)
{
printf("son\n");
}
static Parent* createPeople(void)
{
return new Son;
}
/* daughter.h */
#include "parent.h"
class Daughter : public Parent
{
virtual void hello(void);
};
extern "C" static Parent* createPeople(void);
/* daughter.cpp */
#include <stdio.h>
#include "daughter.h"
void Daughter::hello(void)
{
printf("daughter\n");
}
static Parent* createPeople(void)
{
return new Daughter;
}
/* test.cpp */
#include <stdio.h>
#include <dlfcn.h>
#include "parent.h"
typedef Parent* (Func)(void);
int main(void)
{
void* handle = dlopen("./daughter.so", RTLD_LAZY);
if (handle)
{
Func* f = (Func*)dlsym(handle, "createPeople");
if (f)
{
Parent* p = f();
if (p)
{
p->hello();
}
}
else
{
printf("dlsym:%s\n", dlerror());
}
}
else
{
printf("dlopen:%s\n", dlerror());
}
}
/* parent.h */
class Parent
{
public:
virtual void hello(void)=0;
virtual void bye(void);
};
/* son.h */
#include "parent.h"
class Son : public Parent
{
virtual void hello(void);
};
extern "C" static Parent* createPeople(void);
/* son.cpp */
#include <stdio.h>
#include "son.h"
void Son::hello(void)
{
printf("son\n");
}
static Parent* createPeople(void)
{
return new Son;
}
/* daughter.h */
#include "parent.h"
class Daughter : public Parent
{
virtual void hello(void);
};
extern "C" static Parent* createPeople(void);
/* daughter.cpp */
#include <stdio.h>
#include "daughter.h"
void Daughter::hello(void)
{
printf("daughter\n");
}
static Parent* createPeople(void)
{
return new Daughter;
}
/* test.cpp */
#include <stdio.h>
#include <dlfcn.h>
#include "parent.h"
typedef Parent* (Func)(void);
int main(void)
{
void* handle = dlopen("./daughter.so", RTLD_LAZY);
if (handle)
{
Func* f = (Func*)dlsym(handle, "createPeople");
if (f)
{
Parent* p = f();
if (p)
{
p->hello();
}
}
else
{
printf("dlsym:%s\n", dlerror());
}
}
else
{
printf("dlopen:%s\n", dlerror());
}
}
代码如上,现在编译链接:
g++ -shared son.cpp -o son.so -fPIC
g++ -shared daughter.cpp -o daughter.so -fPIC
g++ test.cpp -o test -ldl
g++ -shared daughter.cpp -o daughter.so -fPIC
g++ test.cpp -o test -ldl
运行test,报错:
dlopen:./daughter.so: undefined symbol: _ZTV6Parent
找不到符号Parent,那么nm daughter.so看看是不是没有Parent这个符号,结果看到:
....
U _ZTI6Parent
0000000000100f00 V _ZTI8Daughter
0000000000000ba0 V _ZTS8Daughter
U _ZTV6Parent
0000000000100f00 V _ZTI8Daughter
0000000000000ba0 V _ZTS8Daughter
U _ZTV6Parent
...
居然有两个Parent符号!其中_ZTV6Parent就是dlopen报找不到错误的那个。初遇这个错误让人头晕,哪里蹦出来两个
Parent?仔细检查最后才发现,Parent有两个虚函数,一个是纯虚函数,一个是普通的虚函数,编译器为这两个虚函数分别生成了两个入口表
_ZTI6Parent和_ZTV6Parent,所以最后链接错误。
改正的方法是干脆把两个虚函数都改为纯虚,当然,这只是很多修改方案中的一个。这里最重要的结论是g++对纯虚函数和虚函数会生成两个链接符号入口,知道这一点,再见到这种链接错误就能处理了。
相关文章
- [c++] 小心析构函数 - 07 22, 2010
- fedora 9 小集 - 01 05, 2009
- 多线程调试 - 12 17, 2008
留言: