2

我有一个看起来像这样的令牌类:

class Token
{
 public:
   typedef enum { STRTOK, INTTOK } Type;
   virtual bool IsA(Type) = 0;
}

class IntTok : public Token
{
   int data;
 public:
   bool IsA(Type t) { return (t == INTTOK); }
   int GetData() { return data; }
}

IntTok newToken;
if ( newToken.IsA(Token::INTTOK )
{
  //blah blah
}

所以基本上我必须在 Token 类中定义每个子类;结果并没有那么糟糕,因为子类很少,我无法想象它们会发生变化。但是,与使用动态转换识别子类相比,它仍然丑陋、笨拙且“正确”。然而:

IntTok newToken;
IntTok* tmpTokenTest = dynamic_cast<IntTok*>(&newToken);
if ( tmpTokenTest != NULL )
{
  //blah blah
}

也很笨拙。特别是当我必须将它们串在一个大的嵌套 if 中时。

那你会用哪个?这个问题还有其他解决方案吗?

注意:我知道无论如何我都必须强制他们获取各自的数据,但是

  1. 在我使用它们的功能之前,我不会施放它们,所以感觉更干净
  2. 我比使用他们的数据更频繁地测试他们的类型。

注意2:上面代码中没有说明的是这些token也是一个链表。这使得模板变得困难(aToken<int>可能指向 aToken<string>等)。这就是为什么我需要一个 Token 类作为父类开始的原因。

4

5 回答 5

3

确实是访客模式

class TokenVisitor {
public:
    virtual ~TokenVisitor() { }
    virtual void visit(IntTok&) = 0;
    virtual void visit(StrTok&) = 0;
};

class Token {
 public:
   virtual void accept(TokenVisitor &v) = 0;
};

class IntTok : public Token {
   int data;
 public:
   virtual void accept(TokenVisitor &v) {
       v.visit(*this);
   }
   int GetData() { return data; }
};

然后只需实现访问者接口并调用

token->accept(myVisitor);

控制权将交给访问者,然后访问者可以执行适当的操作。如果您需要在本地使用正确类型的变量 - 那么您将很难绕过向下转换它。但我认为使用虚拟功能驱动对特定实现的控制通常是解决它的好方法。

于 2009-02-22T19:17:46.170 回答
3

只需使用虚函数来做你想做的事。而不是这个:

if(newToken.IsA(Token::INTTOK))
{
    // do stuff with ((IntTok*)&newToken)->GetData()
}

做这个:

class Token
{
public:
    ...
    virtual void doTypeDependentStuff() {}  // empty default implementation
}

class IntTok : public Token
{
public:
    ...
    void doTypeDependent()
    {
        // do stuff with data
    }
}
于 2009-02-22T18:47:26.070 回答
2

我是否建议使用 Boost::Variant,它基本上是多种类型的联合(variant 类型的对象可以包含 Ti (1 <= i <= n) 类型的任何对象)。

使用它,您将不必使用继承。

那里了解更多信息。

于 2009-02-23T08:13:07.943 回答
0

所以基本上我必须在 Token 类中定义每个子类

你能解释一下为什么吗?

真的有必要投吗?可以使用多态函数。

或者,也许您可​​以拥有一个模板化的 Token 类(对某些具有默认行为)并专门处理其余的。

于 2009-02-22T18:47:56.193 回答
0

这是一个令人讨厌的问题,尽管我更有可能使用使用 RTTI 的版本。

新的 C++ 编译器(我上次在 VC 6.0 中尝试过,当时它不被真正支持)不是应该使用 typeid 运算符,因此您不需要完整的动态转换吗?

于 2009-02-22T18:50:31.960 回答