c语言令牌大全,关于解析:用C ++编写的令牌生成器的继承设计

这篇博客讨论了在C++中如何在不使用动态分配的情况下实现多态,以避免对象切片和内存泄漏问题。通过使用模板和boost::variant,博主提出了一种解决方案,即创建一个无继承的Token类,利用variant来存储不同类型的令牌,同时使用静态访问者模式来处理不同类型的操作。这种方法保持了性能和内存管理的优势,同时也解决了多态性问题。
摘要由CSDN通过智能技术生成

我正在用C ++写一个简单的解析器,旨在解析s表达式语言的子集。

我正在尝试以一种干净的方式为令牌生成器设计继承层次结构,但是由于我一直在尝试避免动态分配,因此我遇到了对象切片问题。我想避免动态分配的原因是避免在令牌生成器和解析器中引入内存泄漏的问题。

总体结构为:解析器具有Tokenizer实例。解析器调用Tokenizer :: peek(),该令牌返回输入开头的令牌。我希望peek()按值返回Token实例,而不是动态分配正确派生类的Token并返回指针。

更具体地说,假设有两种令牌类型:Int和Float。这是一个示例,希望可以解决此问题:

class Token {

public:

virtual std::string str() { return"default"; }

};

template

class BaseToken : public Token {

public:

T value;

BaseToken(const T &t) : value(t) {}

virtual std::string str() {

return to_str(value);

}

};

class TokenInt : public BaseToken {

public:

TokenInt(int i) : BaseToken(i) {}

};

class TokenFloat : public BaseToken {

TokenFloat(float f) : BaseToken(f) {}

};

Token peek() {

return TokenInt(10);

}

int main() {

Token t = peek();

std::cout <

";

return 0;

}

很明显,由于将TokenInt切成一个Token,因此输出为" Token is:default"而不是" Token is:10"。

我的问题是:是否有适当的继承结构或设计模式可以在不使用动态分配的情况下实现这种类型的多态性?

将动态内存分配与智能指针一起使用。 动态内存分配将解决对象切片问题。 智能指针将解决内存管理问题。

因此,扩展我的评论,您可以使用boost :: variant。该文档上有一个很好的v教程(http://www.boost.org/doc/libs/1_57_0/doc/html/variant.html),但这是在您的情况下如何使用它的示例(注意-我添加了一些功能来展示如何使用极为方便的static_visitor)

Boost :: variant也是仅标头的,因此链接时不需要特别注意。

(注意-您可以直接使用boost :: variant作为Token类型;但是,如果将其封装在类中,则可以将访问者的使用隐藏在类方法内)

#include

#include

#include

typedef boost::variant<:string int float> TokenData;

// Define a function overloaded on the different variant contained types:

std::string type_string(int i)

{

return"Integer";

}

std::string type_string(std::string const& s)

{

return"String";

}

std::string type_string(float f)

{

return"Float";

}

// Visitors implement type specific behavior. See the boost::variant docs

// for some more interesting visitors (recursive, multiple dispatch, etc)

class TypeVisitor : public boost::static_visitor<:string>  {

public:

template

std::string operator()(T const& val) const

{

return type_string(val);

}

};

// Token class - no inheritance, so no possible slicing!

class Token {

public:

template

Token(const T& value):

m_value(value)

{}

std::string str() const {

// Variants by default have their stream operators defined to act

// on the contained type. You might want to just define operator<<

// for the Token class (see below), but I'm copying your method

// signature here.

std::stringstream sstr;

sstr << m_value;

return sstr.str();

}

std::string token_type() const {

// Note: you can actually just use m_value.type() to get the type_info for

// the variant's type and do a lookup based on that; however, this shows how

// to use a static_visitor to do different things based on type

return boost::apply_visitor(TypeVisitor(), m_value);

}

private:

TokenData m_value;

friend

std::ostream& operator<

};

// An alternative to the"str" method

std::ostream& operator<

{

return oo << tok.m_value;

}

int main(){

Token t1(10), t2("Hello"), t3(1.5f);

std::cout <

";

std::cout <

";

// Use Token::operator<< instead:

std::cout <

";

}

输出:

Token 1 is: 10 Type: Integer

Token 2 is: Hello Type: String

Token 3 is: 1.3 Type: Float

为了返回一个值,您必须知道它的大小。唯一的方法是:

返回注释中建议的指向基本令牌类型的智能指针,

返回所有您根据类型标签转换的令牌类型的并集,或者

返回包含类型标签和匹配文本的通用令牌类型

令人遗憾的数字2和3实在令人痛苦(#2因为联合是一种痛苦,#3因为抽象包含值的类型很痛苦),因为确实没有充分的理由分词器应该分配任何东西。

工会尤其是痛苦。 非POD类。 ID建议使用有区别的联合-特别是boost :: variant。 它基于堆栈,因此您可以避免任何动态分配问题,并且IMO非常易于使用。

@Anna,您应该写下一个答案。 您的想法对我来说似乎是一个胜利者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值