简体   繁体   中英

How should I distinguish between subclasses

I have a token class that looks something like this:

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
}

So essentially I have to have every subclass defined in the Token class; which doesn't turn out that bad because there are very few subclasses and I can't imagine them changing. But still, it's ugly, kludgy and less "correct" than identifying subclasses using a dynamic cast. However:

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

Is also pretty kludgy. Particularly when I have to string them together in a large, nested if.

So which would you use? Is there another solution to this problem?

Note: I know that I'll have to cast them to get at their respective data anyways, but

  1. I won't be casting them until right before I use their function, so it feels cleaner and
  2. I test their type far more often then I use their data.

Note2: Not indicated in the code above is that these tokens are also a linked list. That makes templating difficult(a Token<int> may point to a Token<string> , etc). Which is why I need a Token class as a parent to begin with.

Just use virtual functions instead to do what you want. Instead of this:

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

Do this:

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

class IntTok : public Token
{
public:
    ...
    void doTypeDependent()
    {
        // do stuff with data
    }
}

Visitor pattern , indeed.

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

Then just implement the visitor interface and call

token->accept(myVisitor);

Control will be given to the Visitor, which then can do the appropriate action(s). If you need to have the variable locally and of the right type - then however you will hardly get around down-casting it. But i think driving control to specific implementations using virtual functions often is a good way to solve it.

Might i suggest using Boost::Variant, which is basically the union of multiple types (an object of type variant can hold any object of type Ti ( 1 <= i <= n ) ).

Using this, you won't have to use inheritance.

See there for more information.

So essentially I have to have every subclass defined in the Token class

Can you explain why?

Is it really necessary to cast? Polymorphic functions can be put to use.

Or, maybe you can have a templated Token class (with default behavior for some) and specialize for the remaining.

That's a nasty one, though I would be more likely to go with the version of using RTTI.

Weren't new C++ compilers (I've last tried in VC 6.0 when it wasn't really supported) supposed the typeid operator so you wouldn't need a full dynamic cast?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM