C++ OOP:如何避免类型切换?

问题描述 投票:0回答:1

背景

我正在编写一个自定义表达式评估器,以进一步了解它是如何工作的。我目前正处于代币化的第一阶段。

我之前在不同的编程语言(Python 和 C#)中多次遇到以下问题,但我不明白应该如何正确处理这个问题。

问题

我想将存储为字符串的表达式转换为标记向量,以便稍后用于计算表达式。我不想只存储字符串向量,因为在评估过程中处理起来有点烦人。

以下是一些示例令牌:

  • 存储值的数字令牌
  • 存储运算符类型的运算符令牌
  • 存储该括号是左括号还是右括号的括号标记

当然,将这些标记存储在向量中意味着我稍后必须读取该标记,这就是问题的关键所在。

如何创建满足这些要求的类结构?

尝试

我首先尝试根据它们所拥有的内容创建类,并且所有类都继承自基类。

(以下代码仅显示声明。)

class Token {};

class NumberToken : public Token {
public:
    int value;
    NumberToken(int value);
};

class OperatorToken : public Token {
public:
    OperatorType operator_type;
    OperatorToken(OperatorType operator_type);
};

class BracketToken : public Token {
public:
    BracketType bracket_type;
    BracketToken(BracketType bracket_type);
};

我遇到的问题是在将它们全部放入向量并尝试从中读取时遇到的:

using sptr = std::shared_ptr; // Only used for readability purposes in this code snippet.

// Creating the vector is nice!
sptr<NumberToken> num = std::make_shared<NumberToken>(NumberToken(100));
sptr<OperatorToken> op = std::make_shared<OperatorToken>(OperatorToken(OperatorType::Addition));
sptr<BracketToken> br = std::make_shared<BracketToken>(BracketToken(BracketType::Open));
std::vector<sptr<Token>> tokens = {num, op, br};

// But reading from it requires dynamic_cast which from what I heard means is an indication of bad code design due to it being type switching...
for (sptr<Token> token : tokens) {
    if (NumberToken* numToken = dynamic_cast<NumberToken*>(token)) {
        // code for handing a number token
    } else if (OperatorToken* opToken = dynamic_cast<OperatorToken*>(token)) {
        // code for handing an operator token
    }
    ...
}

我的第二次尝试涉及基类,只是将每个类的所有不同方法作为纯虚拟方法,但是..显然这是不对的。例如,NumberToken 类将具有没有任何意义的operator_type 字段。

c++ oop polymorphism
1个回答
0
投票

像您一样存储为通用类型很好,但在某些时候(并非总是)您必须知道您正在操作哪种类型。

动态演员阵容在这种情况下有效。

唯一的缺点是,找到真正位于下面的类型可能会非常慢,您必须尝试所有类型。

我建议进行枚举,这样您就可以使用 switch/case 语句,即

O(1)
,而不是一系列
dynamic_cast
,即
O(n)

© www.soinside.com 2019 - 2024. All rights reserved.