我需要解析源代码。我已经确定了3种不同类型的令牌:符号(运算符,关键字),litterals(整数,字符串等)和标识符。
我已经有了以下设计,其基类跟踪子类的类型,因此可以使用基类指针对其进行下载:
class Token
{
type_e type; // E_SYMBOL, E_LITTERAL, E_TOKEN
};
class Symbol : public Token
{
const symbol_e symbol;
};
class Litteral : public Token
{
const Value value;
};
class Identifier : public Token
{
const std::string name;
};
我需要将这些类存储在一个令牌数组中,这就是为什么我需要它们拥有一个公共基类。然后我像这样使用它们:
if( cur->type == E_SYMBOL && static_cast< const Symbol * >( cur )->symbol == E_LPARENT )
{
// ...
}
我可以创建虚拟函数isSymbol,isLitteral,isIdentifer,每个子类都会覆盖,但我仍然需要将基类指针转发到子类指针,以便我可以访问子类的特定数据。
人们说向下倾斜意味着界面可能存在缺陷,并且它使语法非常沉重,所以我想找到另一种方式,但我无法做到。有些人建议访问者模式,但我担心这会无用地复杂化代码,我甚至不理解如何使用访问者模式解决这个问题。
有人可以帮忙吗?谢谢:))
答案 0 :(得分:5)
您有三种选择。每种解决方案都有其优点和缺点。
将逻辑放入令牌类中,因此调用代码不需要知道它正在处理哪种令牌。
这将是&#34;最纯粹的面向对象&#34;解。缺点是逻辑倾向于在基类和子类之间传播,这使得它更难以遵循。它也可能导致类增长相当大。但是编制者/口译员通常不会采取那么多行动来解决这个问题。
有一个接口TokenVisitor
,visit
方法重载了令牌子类型和accept(TokenVisitor&)
Token
方法,每个子类都会覆盖这些方法来调用{的适当重载{1}}。
您现在需要知道界面中完整的令牌类型集,但它允许保持类合理地小,并按行动分组,逻辑通常更容易遵循。
使用受歧视的联合,例如Boost.Variant。
这根本不是面向对象的。它将导致在整个地方切换类型,并可能看起来很难看。但由于逻辑总是在一起,因此通常更容易理解,特别是对于那些不理解代码背后的想法的人。