Есть ли способ не приводить тип при выполнении абстрактного дерева? - PullRequest
0 голосов
/ 14 апреля 2020

Я слышал и видел, почему приведение типов обычно является признаком плохой иерархии / дизайна классов, если только это не из внешней библиотеки, которую вы не можете контролировать. Однако в этом сценарии я совсем не уверен, как этого избежать.

Я разрабатываю небольшую программу, которая выполняет код на основе абстрактного дерева. Все значения получены из одного базового класса Value. Теперь я хочу добавить их, поэтому, прежде всего, проверьте тип, если это разрешено - A->GetType()->HasOperator( "+", { A->GetType(), B->GetType() } ). Возможно, нет необходимости, если я статически анализирую дерево. Но на самом деле проблема заключается в следующем шаге. Скажем A->GetType()->GetOperator( "+" )->Execute( { A, B } ) с подписью virtual Value* Execute( Value* values[] ). Что теперь?

Сам тип Value не может содержать значения, потому что производные классы, такие как Number, знают, как и какой тип информации они имеют (конечно, это относится только к примитивам). типы, а не определенные пользователем, с ними легче иметь дело после того, как вы научитесь обращаться с примитивами). Я действительно не могу определить оператор + для 2 типов чисел, потому что у меня все еще остается 2 Value* s, которые я должен передать этому методу, а затем мне все еще нужно преобразовать их в Number в этом методе.

Одно решение, которое пришло мне в голову, - просто заставить Value иметь двоичную информацию, работать с примитивами в двоичном формате и ... Прежде всего, это просто приведение типов с дополнительными шагами в меньшем масштабе. Во-вторых, это много работы. В-третьих, можно также построить двоичную машину.

Вторым решением является явное определение всех примитивных операций. Итак, Number* AddNumberToNumber ( Number* A, Number* B ), Number* GetNumberField ( Object object, string name ) et c. для всех примитивов. Кажется утомительным, и я не уверен, возможно ли вообще хранить его разумным способом. Прямо сейчас выполнение кода работает как стек - каждый Instruction после выполнения оставляет больше Instruction s в стеке кода. Так что, если бы я сделал это, мне пришлось бы определять целый производный класс для каждого оператора вместо одного делегата для каждого. (Я думаю, что это работает, но это не обобщает хорошо, и если бы я должен был проанализировать текст в коде, мне нужно было бы статически проанализировать его и иметь помехи if..else для каждой операции вместо, скажем, LUT Operator -> [ List of accepted types, Delegate ] Другими словами, я думаю, что это решение будет беспорядок). Я предпочел бы иметь это или что-то подобное:

standardOperators = new map< ... > {
    { "+",
        { { types::number, types::number }, [ some delegate ] },
        { ... },
        ...
    },
    { "-",
        ...
    },
    ...
};

Итак, есть ли лучшее решение? Или приведение типов является лучшим вариантом на этом уровне мастеринга?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...