наследование — C ++ Как избежать даункинга

Мне нужно разобрать исходный код. Я идентифицировал 3 различных типа токенов: символы (операторы, ключевые слова), литералы (целые числа, строки и т. Д.) И идентификаторы.

У меня уже есть следующий дизайн, с базовым классом, который отслеживает тип подкласса, так что его можно уменьшить с помощью указателя базового класса:

class Token
{
type_e type; // E_SYMBOL, E_LITTERAL, E_TOKEN
};

class Symbol : public Token
{
const symbol_e symbol;
};

class Litteral : public Token
{
const Value value;
};

class Identifier : public Token
{
const std::string name;
};

Мне нужно, чтобы эти классы хранились в одном массиве токенов, поэтому мне нужно, чтобы они имели общий базовый класс. Тогда я использую их так:

if( cur->type == E_SYMBOL && static_cast< const Symbol * >( cur )->symbol == E_LPARENT )
{
// ...
}

Я мог бы создать виртуальные функции isSymbol, isLitteral, isIdentifer, которые будут переопределять каждый подкласс, но мне все равно придется понизить указатель базового класса на указатель подкласса. так что я могу получить доступ к конкретным данным подкласса.

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

Кто-нибудь может помочь? Спасибо 🙂

3

Решение

У вас есть три варианта. Каждое решение имеет свои преимущества и недостатки.

  • Поместите логику в классы токенов, чтобы вызывающему коду не нужно было знать, с каким токеном он имеет дело.

    Это было бы «самым чистым объектно-ориентированным» решением. Недостатком является то, что логика имеет тенденцию распространяться между базовым классом и подклассами, что усложняет следование. Это также может привести к тому, что классы вырастут довольно большими. Но у компиляторов / интерпретаторов обычно не так много действий, чтобы это было проблемой.

  • Использовать Шаблон посетителя.

    То есть есть интерфейс TokenVisitor с visit метод перегружен для подтипов токена и accept(TokenVisitor&) метод на Token который каждый подкласс переопределит, чтобы вызвать соответствующую перегрузку visit,

    Теперь вам нужно знать полный набор типов токенов в интерфейсе, но он позволяет сохранять классы достаточно небольшими и сгруппированными по действиям, за которыми обычно легче следовать логике.

  • Например, используйте дискриминационный союз Boost.Variant.

    Это не объектно-ориентированный вообще. Это приведет к переключению типа повсюду и, вероятно, будет выглядеть ужасно. Но так как логика — все вместе, часто легче следовать, особенно для кого-то, кто не понимает идею позади кода.

5

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector