对'vtable for class'的未定义引用

Undefined Reference to 'vtable for class'

本文关键字:未定义 引用 vtable for class      更新时间:2023-10-16

我正在C++中实现一个访问者类,该类为解析树生成XML输出。

当我在 Windows 上使用 Clion 编译时,代码会编译,但是当它在输出预期内容后运行时,它会崩溃。 错误代码是这个

进程已完成,退出代码为 -1073741819 (0xC0000005)

当我尝试使用 gcc(没有 Clion)进行编译时,我收到错误消息

对"vtable for PrintXMLVisitor"的未定义引用。

我的代码如下。 我已经将其蒸馏到产生错误的最小量

阿斯特诺德

#ifndef MINILANG_ASTNODE_H
#define MINILANG_ASTNODE_H
#include <memory>
class Visitor;
class ASTNode {
public:
virtual void accept(std::shared_ptr<Visitor> visitor) = 0;
};

#endif //MINILANG_ASTNODE_H

ASTTypeNode.h

#ifndef MINILANG_ASTTYPENODE_H
#define MINILANG_ASTTYPENODE_H

#include "ASTNode.h"
class ASTTypeNode: public ASTNode {
public:
enum Type {Real, Int, Bool, String};
ASTTypeNode(Type type);
Type getType() const;
void accept(std::shared_ptr<Visitor> visitor) override;
private:
Type type;
};

#endif //MINILANG_ASTTYPENODE_H

ASTTypeNode.cpp

#include "ASTTypeNode.h"
#include "Visitor.h"
ASTTypeNode::ASTTypeNode(ASTTypeNode::Type type)
: type(type)
{
}
ASTTypeNode::Type ASTTypeNode::getType() const {
return type;
}
void ASTTypeNode::accept(std::shared_ptr<Visitor> visitor) {
visitor->visit(std::shared_ptr<ASTTypeNode>(this));
}

访客.h

#ifndef MINILANG_VISITOR_H
#define MINILANG_VISITOR_H
#include <memory>
#include "ASTTypeNode.h"

class Visitor {
public:
virtual void visit(std::shared_ptr<ASTTypeNode> typeNode) = 0;
};

#endif //MINILANG_VISITOR_H

PrintXMLVisitor.h

#ifndef MINILANG_PRINTXMLVISITOR_H
#define MINILANG_PRINTXMLVISITOR_H

#include "Visitor.h"
class PrintXMLVisitor: public Visitor {
public:
void visit(std::shared_ptr<ASTTypeNode> typeNode) override;
};

#endif //MINILANG_PRINTXMLVISITOR_H

PrintXMLVisitor.cpp

#include "PrintXMLVisitor.h"
#include <iostream>
void PrintXMLVisitor::visit(std::shared_ptr<ASTTypeNode> typeNode) {
std::string typeName;
switch(typeNode->getType())
{
case ASTTypeNode::Type::Real:
typeName = "Real";
break;
case ASTTypeNode::Type::Int:
typeName = "Int";
break;
case ASTTypeNode::Type::Bool:
typeName = "Bool";
break;
case ASTTypeNode::Type::String:
typeName = "String";
break;
default:
typeName = "Error";
exit(22);
}
std::cout << "<TypeNode>" << typeName << "</TypeNode>" << std:: endl;
}

主.cpp

#include <iostream>
#include "Lexer.h"
#include "ASTTypeNode.h"
#include "PrintXMLVisitor.h"
int main() {
ASTTypeNode astTypeNode (ASTTypeNode::Type::Int);
astTypeNode.accept(std::make_shared<PrintXMLVisitor>());

return 0;
}

您正在制作一个非动态的共享指针。具体说来

void ASTTypeNode::accept(std::shared_ptr<Visitor> visitor) {
visitor->visit(std::shared_ptr<ASTTypeNode>(this)); // <=== HERE
}

该声明中的this是指:

int main() 
{
ASTTypeNode astTypeNode (ASTTypeNode::Type::Int); // <== this object
astTypeNode.accept(std::make_shared<PrintXMLVisitor>());
return 0;
}

更改工具链并不能解决此问题,您可以选择,最明显的两个是:

  • 停止对访问参数使用std::shared_ptr
  • 使用标准库的std:enable_shared_from_this功能管理所有需要std::shared_ptr管理和从this共享的ASTNodeType实例。

前者是显而易见的(或者至少现在是),所以我不会进一步讨论它。后者不一定是微不足道的,因为它要求使用shared_from_this的基础类的任何实例都必须由std::shared_ptr包装器管理。也就是说,没有像您目前在main()所做的那样的具体结构。这可能会对整体代码库产生重大影响,因此请谨慎选择。

上述方法在您的情况下如何工作的示例:

首先,将ASTNodeType的派生链更改为如下所示:

class ASTTypeNode
: public ASTNode
, public std::enable_shared_from_this<ASTTypeNode> // ADDED

接下来,按如下方式利用shared_from_this

void ASTTypeNode::accept(std::shared_ptr<Visitor> visitor) 
{
visitor->visit(shared_from_this()); // HERE
}

最后,通过执行以下操作来履行您所做的保证,即ASTNodeType实例都是共享 ptr 管理的:

int main() 
{
std::shared_ptr<ASTTypeNode> astTypeNode = std::make_shared<ASTTypeNode>(ASTTypeNode::Type::Int);
astTypeNode->accept(std::make_shared<PrintXMLVisitor>());
return 0;
}

这应该行得通。在此处阅读有关上述代码中使用的内容的更多信息:

  • std::enable_shared_from_this
  • std::enable_shared_from_this::shared_from_this

正如我所说,所有这些都是为了便于使用仅给定this指针的对象中的std::shared_ptr。如果您可以首先删除该要求,这可能是一条更容易的途径,我会首先考虑这一点。