据推测,链接器引用了对 vtable 的未定义引用
Linker refers to, supposedly, undefined reference to vtable
我正在尝试使用抽象 class 来表示子类型的公共基础。但是,无论我做什么,它(它似乎是链接器)都会抱怨 vtables 和未定义的引用。从错误消息来看,问题一定与析构函数有关。够奇怪的,它一直在谈论一个
"undefined reference to 'AbstractBase::~AbstractBase()'"
in child.cpp 这毫无意义。
和上次一样,我实际上不能展示我的代码,所以这里有一个本质上做同样事情的例子:
首先是摘要class,"AbstractBase.h":
#ifndef ABSTRACTBASE
#define ABSTRACTBASE
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
}
#endif
使用abstractbase的child,"child.h":
#ifndef CHILD
#define CHILD
class child : public AbstractBase
{
public:
~child() override;
}
#endif
"child.cpp"中的实现:
#include "child.h"
child::~child()
显然有更多的功能,但本质上这就是我真正的 class 的析构函数的样子。
在网上搜索了在 C++ 中使用抽象 classes 的方法后,我准备放弃了。据我从这些消息来源可以看出,这是做到这一点的方法。您将摘要 class 的析构函数声明为虚拟的,因此对它的任何调用都将包含 child。 child 的析构函数只是标记为覆盖。应该没有别的了。
我在这里错过了一些真正基本的东西吗?
PS: 添加了 MCVE:
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
};
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
~child() override
{}
}
int main (argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
我要补充一点,我现在得到的错误并不完全相同,而原来的错误是这样的:
undefined reference to 'vtable for AbstractBase': In function
AbstractBase:~AbstractBase()': Undefined reference to 'vtable for
AbstractBase': Undefined reference to 'typeinfo for AbstractBase':
Collect2:error:ld returned 1 exit status
你需要为每个class定义一个析构函数,否则你不能销毁那个class的对象(包括成员对象和基子对象)对象):
class AbstractBase
{
public:
virtual ~AbstractBase() = default;
}; // ^^^^^^^^^^^
一些替代公式:
用户自定义:
struct AbstractBase {
virtual ~AbstractBase() {}
};
纯虚拟,但定义:
struct AbstractBase {
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() = default;
即使您没有其他虚拟成员函数,这样做的好处是可以保留 class 抽象。
结合两者:
struct AbstractBase {
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() {}
感谢大家的帮助。我最终偶然发现了一个解决方案。
显然,在抽象 class 中使用常规虚函数会导致这些问题。我在我的 MCVE 中重新创建了修复和错误,观察:
无效代码:
class AbstractBase
{
public:
virtual void idiot();
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase()=default;
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
void idiot() override
{
}
~child() override
{
}
};
int main(int argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
功能代码:
class AbstractBase
{
public:
//virtual void idiot();
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase()=default;
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
/*void idiot() override
{
}*/
~child() override
{
}
};
int main(int argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
请注意我所做的 仅 更改,正在注释掉虚函数白痴,并且它在 child 中实现。
在我看来,这是不合逻辑的。这个额外的功能应该不会造成问题。
或者,这是真正的解决方案,可以使所有虚函数成为纯函数。这解决了问题。
我只能猜测这里发生了什么,它似乎在 AbstractBase.cpp 中寻找非纯函数的实现,这当然不存在。结果是关于对所述 AbstractBase 的虚表和类型信息的未定义引用的讨论,声明虚函数确实未定义是正确的。但它不应该在意,class 是抽象的。
我的结论是,如果这是预期的功能,如果您要在 C++ 中使用抽象 classes,您确实需要将所有函数声明为纯函数,即使逻辑表明这是不必要的。无论如何,如果它确实是有意的,那么编译器应该警告用户。目前的错误信息完全没有用。
我正在尝试使用抽象 class 来表示子类型的公共基础。但是,无论我做什么,它(它似乎是链接器)都会抱怨 vtables 和未定义的引用。从错误消息来看,问题一定与析构函数有关。够奇怪的,它一直在谈论一个
"undefined reference to 'AbstractBase::~AbstractBase()'"
in child.cpp 这毫无意义。
和上次一样,我实际上不能展示我的代码,所以这里有一个本质上做同样事情的例子:
首先是摘要class,"AbstractBase.h":
#ifndef ABSTRACTBASE
#define ABSTRACTBASE
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
}
#endif
使用abstractbase的child,"child.h":
#ifndef CHILD
#define CHILD
class child : public AbstractBase
{
public:
~child() override;
}
#endif
"child.cpp"中的实现:
#include "child.h"
child::~child()
显然有更多的功能,但本质上这就是我真正的 class 的析构函数的样子。
在网上搜索了在 C++ 中使用抽象 classes 的方法后,我准备放弃了。据我从这些消息来源可以看出,这是做到这一点的方法。您将摘要 class 的析构函数声明为虚拟的,因此对它的任何调用都将包含 child。 child 的析构函数只是标记为覆盖。应该没有别的了。
我在这里错过了一些真正基本的东西吗?
PS: 添加了 MCVE:
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
};
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
~child() override
{}
}
int main (argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
我要补充一点,我现在得到的错误并不完全相同,而原来的错误是这样的:
undefined reference to 'vtable for AbstractBase': In function AbstractBase:~AbstractBase()': Undefined reference to 'vtable for AbstractBase': Undefined reference to 'typeinfo for AbstractBase': Collect2:error:ld returned 1 exit status
你需要为每个class定义一个析构函数,否则你不能销毁那个class的对象(包括成员对象和基子对象)对象):
class AbstractBase
{
public:
virtual ~AbstractBase() = default;
}; // ^^^^^^^^^^^
一些替代公式:
用户自定义:
struct AbstractBase { virtual ~AbstractBase() {} };
纯虚拟,但定义:
struct AbstractBase { virtual ~AbstractBase() = 0; }; AbstractBase::~AbstractBase() = default;
即使您没有其他虚拟成员函数,这样做的好处是可以保留 class 抽象。
结合两者:
struct AbstractBase { virtual ~AbstractBase() = 0; }; AbstractBase::~AbstractBase() {}
感谢大家的帮助。我最终偶然发现了一个解决方案。
显然,在抽象 class 中使用常规虚函数会导致这些问题。我在我的 MCVE 中重新创建了修复和错误,观察:
无效代码:
class AbstractBase
{
public:
virtual void idiot();
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase()=default;
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
void idiot() override
{
}
~child() override
{
}
};
int main(int argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
功能代码:
class AbstractBase
{
public:
//virtual void idiot();
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase()=default;
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
/*void idiot() override
{
}*/
~child() override
{
}
};
int main(int argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
请注意我所做的 仅 更改,正在注释掉虚函数白痴,并且它在 child 中实现。
在我看来,这是不合逻辑的。这个额外的功能应该不会造成问题。
或者,这是真正的解决方案,可以使所有虚函数成为纯函数。这解决了问题。
我只能猜测这里发生了什么,它似乎在 AbstractBase.cpp 中寻找非纯函数的实现,这当然不存在。结果是关于对所述 AbstractBase 的虚表和类型信息的未定义引用的讨论,声明虚函数确实未定义是正确的。但它不应该在意,class 是抽象的。
我的结论是,如果这是预期的功能,如果您要在 C++ 中使用抽象 classes,您确实需要将所有函数声明为纯函数,即使逻辑表明这是不必要的。无论如何,如果它确实是有意的,那么编译器应该警告用户。目前的错误信息完全没有用。