我应该如何区分子类

时间:2009-02-22 18:41:10

标签: c++ inheritance coding-style dynamic-cast

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

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. 我经常测试他们的类型然后我使用他们的数据。
  3. 注意2:上面的代码中没有指出这些令牌也是一个链表。这会使模板变得困难(Token<int>可能指向Token<string>等。这就是为什么我需要一个Token类作为父类开始。

5 个答案:

答案 0 :(得分: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
    }
}

答案 1 :(得分:3)

确实

Visitor pattern

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);

将向访问者提供控制权,然后访问者可以采取适当的措施。如果你需要在本地和正确的类型中使用变量 - 那么你将难以绕过它。但我认为使用虚函数驱动控制到特定实现通常是解决它的好方法。

答案 2 :(得分:2)

我建议使用Boost :: Variant,它基本上是多种类型的联合(类型变量的对象可以容纳Ti类型的任何对象(1&lt; = i&lt; = n))。

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

有关详细信息,请参阅there

答案 3 :(得分:0)

  

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

你能解释一下原因吗?

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

或者,也许你可以有一个模板化的Token类(对某些人有默认行为)并且专门用于剩下的。

答案 4 :(得分:0)

这是一个令人讨厌的问题,但我更倾向于选择使用RTTI的版本。

不是新的C ++编译器(我最后在VC 6.0中尝试过,当它不受支持时)假设是typeid运算符,所以你不需要一个完整的动态转换?