2015-01-07 2 views
1

Я пытаюсь переобучить биты о наследовании C++, а также написать программу, которая оценивает простые математические выражения (как строки) с нуля для практики, но я сталкиваюсь с большим количеством проблемы. Мой единственный предыдущий опыт работы с lexing, как это, с OCaml (и Ocamllex/yacc), и это совсем немного отличается.C++ Tokenizing математическое выражение с использованием классов

Во всяком случае, я создал простой токен класса:

class Token{ 
    public: 
     string type; 
     string characters; 
}; 

Где type является строкой, которая сообщает тип маркеров (плюс, минус, и т.д.) и characters является строкой, что маркер на самом деле состоит из. Из этого я сделал производные классы для каждого токена. Вот один для +:

class Plus: public Token{ 
    public: 
     Plus(){ 
      type = "plus"; 
      characters = "+"; 
     } 
}; 

Minus, Times, DividedBy, LeftParenthesis, RightParenthesis и Number все сделали то же самое. Однако для Number я хотел добавить в double, в котором хранится значение токена, поэтому он также включает в себя общедоступную переменную double value, и ее конструктор устанавливает это значение. Вероятно, вы можете увидеть, где здесь возникнут проблемы, и я немного доберусь до них.

У меня есть функция, которая считывает строку, разбивает его на эти подстроки, и сохраняет его как вектор строк (So "3.2 +( -1.83)" возвращает вектор со струнами "3.2", "+", "(", "-1.83" и ")"). У меня есть еще один, который превращает все это в объекты Token и сохраняет его как вектор Token (так он делает вещи вроде tokens.push_back(LeftParenthesis());).

Теперь я хочу взять этот вектор токена и сделать с ним все. (Цель состоит в том, чтобы использовать алгоритм маневрового двора, чтобы поместить его в обратную польскую нотацию, а затем оценить его.) Однако у меня много проблем, в основном из-за того, что я использую вектор Token, и каждый элемент это производный тип токена.

Самая большая проблема в том, что я не могу получить доступ к элементу value маркеров Number. Я пробовал другие вещи, такие как использование виртуальных функций getter, и он все еще не работает правильно. Другая проблема заключается в том, что единственный способ определить, что такое токен, - это прочитать элемент characters, который, кажется, делает всю вещь подкласса бессмысленной.

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

Edit: В ответ на Thomas Matthews: я играл с виртуальными методами (которые не работают либо), так вот фактический Токен класс и номер, а также:

class Token{ 
public: 
    string type; 
    string characters; 
    virtual double getValue(); 
}; 

class Number: public Token{ 
public: 
    double value; 
    Number(string chars){ 
     type = "number"; 
     characters = chars; 
     value = atof(chars.c_str()); 
    } 
    virtual double getValue(){ 
     return value; 
    } 
}; 

И вот основной метод, который я играю с, который просто принимает случайную строку, я сделал и попытки напечатать его обратно, но при обращении к value элемент любого числа при этом:

int main(){ 
vector<Token> tvec = tokenize("5 + 4 - 11 * (-3.2 + .19)"); 
for(vector<Token>::iterator it = tvec.begin(), end = tvec.end(); it != end; ++it) 
if(it->type == "number") 
    cout << it->getValue(); // doesn't work 
else 
    cout << it->characters; 
cout << endl; 
return 0; 
} 
+0

Показать класс для 'Number' и простую программу' main', которая демонстрирует использование класса. –

+2

Обратите внимание, что при использовании вашего вектора «токенов» вы, вероятно, страдаете [срезом объектов] (http://stackoverflow.com/questions/274626/what-is-object-slicing) при вставке токенов в вектор. См. [Здесь] (http://stackoverflow.com/questions/9241680/list-of-polymorphic-objects) для использования в контейнерах. – Diego

+0

Я добавил класс и простую программу. – chetlin

ответ

0

Я предлагаю вам добавить метод, который возвращает значение токена в виде строки.

Это позволит вам преобразовать значение в число.

Возможно, что вы должны думать о том:

  • Какое значение токена используется?
  • Вам нужно указать токен, чтобы оценить данное выражение?

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

+0

Да, я подумал об этом. С этим, тогда нет смысла для токенов, так как я начал с строк, а затем превратил их в токены, затем я бы превратил их в строки. Все, что они сделали бы, это сказать: «вот строка, и вот то, что она представляет». Я думаю, что это чище, чем вызов метода, который читает строку и определяет, что это за все время. – chetlin

2

Проблема заключается в том, что вы используете вектор Tokens (vector<Token>), поэтому в любое время, когда вы пытаетесь вставить один из ваших производных классов в вектор, он создает новый объект Token со значениями, скопированными из базовой части вашего токена класс, а остальное убрали. Это называется object slicing и представляет собой тонкую проблему с C++, в которой работают программисты, у которых есть опыт работы с более динамичными языками OO.

В C++ наследование и объектная ориентация в основном работают только с помощью указателей и ссылок. Если вы хотите иметь общий вектор, который может содержать любой подкласс Token, вам необходимо использовать vector<Token *> со всеми связанными с ним проблемами управления памятью.

+0

или 'vector >' и обойти большинство проблем управления памятью. –

+0

Хорошо, я попробую. Если я использую 'vector ' (называемый 'tvec'), а затем для токена 'Number', я делаю' tvec.push_back (new Number (12.34)) ', а затем имеет итератор' it', указывающий на этот элемент, есть способ получить «значение»? Будет ли я (* it) -> value' или это сложнее? Благодаря! – chetlin

Смежные вопросы