对 'vtable for class' 的未定义引用
Undefined Reference to 'vtable for class'
我正在用 C++ 实现一个 Visitor class,它为解析树生成 XML 输出。
当我在 Windows 上使用 Clion 进行编译时,代码可以编译,但是当它在输出预期内容后运行时会崩溃。错误码是这个
Process finished with exit code -1073741819 (0xC0000005)
当我尝试使用 gcc(没有 Clion)进行编译时,我收到错误消息
Undefined Reference to 'vtable for PrintXMLVisitor'.
我的代码如下。我已经将它提炼到产生错误的最少数量
ASTNode.h
#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));
}
Visitor.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
打印XMLVisitor.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;
}
main.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
作为访问参数。
- 管理所有
ASTNodeType
个需要 std::shared_ptr
管理的实例,并使用标准库的 std:enable_shared_from_this
功能从 this
共享。
前者是显而易见的(或者至少现在),所以我不会进一步讨论它。后者 not 不一定是微不足道的,因为它要求使用 shared_from_this
的基础 class 的任何实例必须由 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
实例是通过这样做管理的共享指针:
int main()
{
std::shared_ptr<ASTTypeNode> astTypeNode = std::make_shared<ASTTypeNode>(ASTTypeNode::Type::Int);
astTypeNode->accept(std::make_shared<PrintXMLVisitor>());
return 0;
}
应该可以。在此处阅读有关上述代码中使用的内容的更多信息:
正如我所说,所有这些都是为了便于从仅给定 this
指针的对象中使用 std::shared_ptr
。如果您能首先删除该要求,这可能是一条更容易采取的途径,我会首先考虑。
我正在用 C++ 实现一个 Visitor class,它为解析树生成 XML 输出。
当我在 Windows 上使用 Clion 进行编译时,代码可以编译,但是当它在输出预期内容后运行时会崩溃。错误码是这个
Process finished with exit code -1073741819 (0xC0000005)
当我尝试使用 gcc(没有 Clion)进行编译时,我收到错误消息
Undefined Reference to 'vtable for PrintXMLVisitor'.
我的代码如下。我已经将它提炼到产生错误的最少数量
ASTNode.h
#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));
}
Visitor.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
打印XMLVisitor.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;
}
main.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
作为访问参数。 - 管理所有
ASTNodeType
个需要std::shared_ptr
管理的实例,并使用标准库的std:enable_shared_from_this
功能从this
共享。
前者是显而易见的(或者至少现在),所以我不会进一步讨论它。后者 not 不一定是微不足道的,因为它要求使用 shared_from_this
的基础 class 的任何实例必须由 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
实例是通过这样做管理的共享指针:
int main()
{
std::shared_ptr<ASTTypeNode> astTypeNode = std::make_shared<ASTTypeNode>(ASTTypeNode::Type::Int);
astTypeNode->accept(std::make_shared<PrintXMLVisitor>());
return 0;
}
应该可以。在此处阅读有关上述代码中使用的内容的更多信息:
正如我所说,所有这些都是为了便于从仅给定 this
指针的对象中使用 std::shared_ptr
。如果您能首先删除该要求,这可能是一条更容易采取的途径,我会首先考虑。