gsoap及其工具wsdl2h和soapcpp2为我提供了一个包含以下内容的soapStub.h文件:
class SOAP_CMAC ns2__SOAPKunden
{
public:
std::string *adresszusatz;
// ...
public:
virtual int soap_type() const { return 7; }
// ...
ns2__SOAPKunden() : adresszusatz(NULL), x(NULL) { } // left out all member init.
virtual ~ns2__SOAPKunden() { }
};
我从一个小应用程序开始,使用该类用informix DB中的数据填充对象。
但要成功编译我必须放弃所有虚拟内容 - 我发现许多关于此错误的帖子以及在子类中使用虚拟成员 - 否则我得到
main.o: In function `ns2__SOAPKunden::ns2__SOAPKunden()':
main.cpp:(.text._ZN15ns2__SOAPKundenC1Ev[ns2__SOAPKunden::ns2__SOAPKunden()]+0xf): undefined reference to `vtable for ns2__SOAPKunden'
main.o: In function `ns2__SOAPKunden::~ns2__SOAPKunden()':
main.cpp:(.text._ZN15ns2__SOAPKundenD1Ev[ns2__SOAPKunden::~ns2__SOAPKunden()]+0x13): undefined reference to `vtable for ns2__SOAPKunden'
collect2: ld returned 1 exit status
我承认经过多年的脚本编写后,我很难理解C ++代码......我想问一下下一步要做什么的建议。我的班级不是派生班级,例如让我惊讶的是什么。
答案 0 :(得分:14)
错误表示虚拟表未在最终二进制文件(可执行文件或库)中正确编译/链接。导致此错误的常见情况有两种:
soapStub.cpp
编译为soapStub.o
,但没有将该二进制文件添加到链接器命令行。对于没有经验的开发人员来说,第二种情况最难识别,并且可能是由标题中定义的类包含虚函数引起的。如果所有虚函数都是内联定义的,编译器将在包含头的所有转换单元中生成虚拟表,并将其标记为弱符号,以便链接器可以丢弃它们,但如果稍后添加新的虚方法,你在标题中保留未定义 - 或者如果从其中一个虚函数中删除定义 - 那么编译器将不会在每个翻译单元中生成虚拟表,而只在定义这些函数的虚拟表中生成。
要检查的事项:
答案 1 :(得分:1)
这就是大卫罗德里格斯所说的,只是简单地说我猜...
我在接口类中遇到过这种情况:
class IBase
{
public:
virtual void begin(unsigned long);
virtual void end();
virtual int available(void) = 0;
virtual int peek(void) = 0;
virtual int read(void) = 0;
virtual void flush(void) = 0;
}
并将其更改为:
class IBase
{
public:
virtual void begin(unsigned long) = 0;
virtual void end() = 0;
virtual int available(void) = 0;
virtual int peek(void) = 0;
virtual int read(void) = 0;
virtual void flush(void) = 0;
}
这就是诀窍。
begin()和end()是在不同文件的派生类中定义的,IBase类(接口)只在头文件中声明并包含在少数几个地方。
当我将优化设置为无(-O0)时,OP出现错误,任何其他设置都没有导致错误(gcc 4.8)。