代码之家  ›  专栏  ›  技术社区  ›  Whaledawg

我应该如何区分子类

  •  2
  • Whaledawg  · 技术社区  · 17 年前

    我有一个token类,看起来像这样:

    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: 上面的代码中没有指出这些令牌也是一个链表。这使得模板制作变得很困难(a) Token<int> 可能指的是 Token<string> 等等)。这就是为什么我首先需要一个令牌类作为父类。

    5 回复  |  直到 17 年前
        1
  •  3
  •   Adam Rosenfield    17 年前

    只需使用虚拟函数即可。而不是这个:

    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
        }
    }
    
        2
  •  3
  •   Johannes Schaub - litb    17 年前

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

    访客将获得控制权,然后可以执行适当的操作。如果你需要在本地使用正确类型的变量,那么你很难找到合适的方法。但我认为,使用虚拟函数将控制驱动到特定的实现通常是解决这个问题的一个好方法。

        3
  •  2
  •   Benoît photo_tom    17 年前

    我是否可以建议使用Boost::Variant,它基本上是多个类型的并集(Variant类型的对象可以容纳Ti(1<=i<=n)类型的任何对象)。

    使用这个,你不必使用继承。

    看见 there 了解更多信息。

        4
  •  0
  •   dirkgently    17 年前

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

    你能解释一下原因吗?

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

    或者,您可以拥有一个模板化的令牌类(对某些令牌类具有默认行为),并对其余的令牌类进行专门化。

        5
  •  0
  •   Uri    17 年前

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

    不是新的C++编译器(我上次在VC 6中尝试过,当它没有真正支持的时候)假设Type ID操作符,这样你就不需要一个完整的动态转换了吗?