2013-08-08 3 views
0

Я пытаюсь построить простой калькулятор с одной операцией, чтобы практиковать такие методы, как while и for, и я пытаюсь изучить и понять способы «меню» в консоли.Взять отфильтрованный пользовательский ввод и сделать его соответствующим опции меню

У меня есть программа, которая дает вам список (записи от map, функция, которую я мог использовать, но почти ничего не знаю) о действиях, из которых вы должны выбрать.

Если вы вводите недопустимый ввод (не целое или целое число вне диапазона), он предлагает вам действительный ответ. Теперь я хочу, чтобы программа взяла записи (1-4) и сделала их соответствующими операции.

В моем коде вы увидите, что каждая операция имеет свой собственный метод (я думал, что это будет хороший способ сделать что-то, особенно для практики работы между методами). Я хочу, чтобы main взял operatorSelection и использовал это, чтобы выбрать, к какому методу перейти. Затем он вычислит result и вернет его на main.

Я думал, что я мог бы достичь, используя map, имеющие operatorSelection соответствуют записи в map, и имеющие соответствующую строку в этой записи будет использоваться для вызова метода (где каждый метод называется так же, как и в map).

Примечание Прежде чем ответить
Я новичок в этом, и я хочу знать, оптимизированный путь об этом. Я хочу, чтобы это было просто, но эффективно; Я не знаю некоторых функций, которые я использую, особенно map. Я кратко прочитал о vector и array, но я не знал, как их использовать. Я понимаю, что map в моей функции, кажется, печатается в алфавитном порядке, и я хотел бы иметь возможность сортировать записи полностью по своему усмотрению. Есть ли лучший способ сделать это, чем с помощью map?

Вот мой код (методы эксплуатации являются неполными, я знаю):

// OneOpCalc.cpp : Defines the entry pofloat for the console application. 

#include "stdafx.h" 
using namespace std; 

int operatorSelection; 
float firstNumber,secondNumber,result; 

int main(float argc, char* argv[]) 
{ 
    bool validInput = false; 

    map<string,int> Operations; 
    Operations.insert(pair<string, int>("Addition", 1)); 
    Operations.insert(pair<string, int>("Division", 2)); 
    Operations.insert(pair<string, int>("Multiplication", 3)); 
    Operations.insert(pair<string, int>("Subtraction", 4)); 

    cout << "Welcome to OneOpCalc. "; 

    while (!validInput) 
    { 
     cout << "Please select an operation by its number: "; 
     cin >> operatorSelection; 
     if (!cin || operatorSelection > 5 || operatorSelection < 1) 
     { 
      cout << "Error: Invalid entry. Try again." << endl << endl; 
      cin.clear(); 
      cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
     } 
     else 
     { 
      validInput = true; 
     } 
    } 

    system("pause"); 
    return 0; 
} 

float Addition (float firstNumber, float secondNumber) 
{ 
    result=firstNumber+secondNumber; 
    return (result); 
} 

float Subtraction (float firstNumber, float secondNumber) 
{ 
    result=firstNumber-secondNumber; 
    return (result); 
} 

float Multiplication (float firstNumber, float secondNumber) 
{ 
    result=firstNumber*secondNumber; 
    return (result); 
} 

float Division (float firstNumber, float secondNumber) 
{ 
    result=firstNumber/secondNumber; 
    return (result); 
} 

Чтобы поставить вопрос просто:
Что такое хороший способ для вызова метода в зависимости от пользовательского ввода?

ответ

1

Чтобы ответить на ваш вопрос: а switch будет уместно (см ниже)

Другие возможности:
map с указателями на функции, как Илья Kobelevskiy упомянул, или вы используете enum для такой вещи вместо карты, если вам нужно все это вообще (посмотрите на enums). Но сначала давайте посмотрим на код:

  • Вы не должны использовать float как argc в вашем main. Счетчик аргументов - это натуральное число, а не float (перелом).
  • Не забудет включает в себя:

    #include <iostream> // for cin/cout 
    #include <map>  // for the map 
    #include <limits> // for numeric_limits<...> 
    
  • Вместо system("pause") вы должны лучше использовать std::cin.get(). Он имеет тот же эффект, но переносится, а также не только работает под Windows.

  • Вместо !cin, которая в основном так же, как cin == null, вы, вероятно, хотите использовать !cin.good()
  • Если у вас есть только 4 операции, не позволяют 5 в качестве входных данных (вы в настоящее время позволяют это)
  • Кроме того, в ваших функциях вы изменяете глобальную переменную result, которая, как я думаю, не была задумана именно так, не так ли? Фактически вы можете напрямую вернуть результат, не сохраняя его где-то раньше.
  • Глобальные переменные - это несколько bad practice. Попытайтесь избежать этого.

Вот рабочий пример кода, который также составляет:

#include "stdafx.h"  // inconvenient unportable windows stuff 

#include <iostream>  // cin and cout 
#include <map>   // the map 
#include <limits>  // numeric_limits 
#include <string>  // strings (obviously) 
using namespace std; 

int operatorSelection; 
float firstNumber,secondNumber,result; 

int main(int argc, char* argv[]) 
{ 
    bool   validInput = false; 
    map<string,int> Operations; 

    Operations.insert(pair<string, int>("Addition",  1)); 
    Operations.insert(pair<string, int>("Division",  2)); 
    Operations.insert(pair<string, int>("Multiplication", 3)); 
    Operations.insert(pair<string, int>("Subtraction", 4)); 

    cout << "Welcome to OneOpCalc. "; 

    while (!validInput) 
    { 
     cout << "Please select an operation by its number: "; 
     cin >> operatorSelection; 
     if (!cin.good() || operatorSelection > 4 || operatorSelection < 1) 
     { 
      cout << "Error: Invalid entry. Try again." << endl << endl; 
      cin.clear(); 
      cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
     } 
     else 
     { 
      validInput = true; 
     } 
    } 

    cin.get(); 
    return 0; 
} 

float Addition (float firstNumber, float secondNumber) 
{ 
    return firstNumber+secondNumber; 
} 

float Subtraction (float firstNumber, float secondNumber) 
{ 
    return firstNumber-secondNumber; 
} 

float Multiplication (float firstNumber, float secondNumber) 
{ 
    return firstNumber*secondNumber; 
} 

float Division (float firstNumber, float secondNumber) 
{ 
    return firstNumber/secondNumber; 
} 

Вот предложение, как ваша окончательная программа может выглядеть следующим образом. Конечно, есть еще много вещей, которые вы могли бы улучшить! (Только для примера: Использование классов и OO кода)

#include "stdafx.h"  // inconvenient unportable windows stuff 

#include <iostream>  // cin and cout 
#include <map>   // the map 
#include <limits>  // numeric_limits 
#include <string>  // strings (obviously) 
#include <cmath>  // for NaN. ATTENTION: for gcc you have to compile with -lm 

using namespace std; 

int main(int argc, char* argv[]) 
{ 
    int operatorSelection; 
    float firstNumber, secondNumber, result; 

    cout << "Welcome to OneOpCalc. "; 

    while (true) 
    { 
     cout << "Please select an operation by its number: "; 
     cin >> operatorSelection; 
     if (!cin.good() || operatorSelection > 4 || operatorSelection < 1) 
     { 
      cout << "Error: Invalid entry. Try again." << endl << endl; 
      cin.clear(); 
      cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
     } 
     else 
     { 
      break; 
     } 
    } 

    do 
    { 
     cin.clear(); 
     cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
     cin >> firstNumber; 
    } while(!cin.good()); 

    do 
    { 
     cin.clear(); 
     cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
     cin >> secondNumber; 
    } while(!cin.good()); 

    switch(operatorSelection) 
    { 
     case 1: 
      result = firstNumber + secondNumber; 
      break; 
     case 2: 
      // don't devide by 0! 
      if(secondNumber == 0.0) 
      { 
       result = NAN; 
      } 
      else 
      { 
       result = firstNumber/secondNumber; 
      } 
      break; 
     case 3: 
      result = firstNumber * secondNumber; 
      break; 
     case 4: 
      result = firstNumber - secondNumber; 
      break; 
     default: 
      cout << "I'm sorry, something went terribly wrong"; 
      return -1; 
    } 

    cout << "Your result is: " << result; 

    cin.ignore(); 
    cin.get(); 
    return 0; 
} 

Вообще-то я могу порекомендовать вам этот link, особенно раздел tutorial. Кроме того, не стесняйтесь google для получения дополнительных уроков и попробуйте примеры.

Еще один совет: Если вы не хотите использовать stdafx.h, отключите предварительно скомпилированные заголовки в свойствах проекта. Посмотрите на this и this.

+0

Вы так много написаны, и все это так полезно, но я все это время тратил на то, чтобы обвести вокруг себя голову. Я заменил 'system (" pause ")' на 'cin.get()', и он не работает. Теперь программа закрывается, как только выполняется 'while'. '! CIN.good() 'работает, хотя и с этим, и с!! cin. Я пытался выяснить, как заставить OneOpCalc обрабатывать пустую запись как ошибочный ввод. – jwarner112

+0

Принятие пяти входных данных было случайным - я строю эту программу, чтобы я мог взять понятия, которые я изучил, и применить их к предыдущему проекту, где мне нужна эта концепция, и там у меня есть 5 вариантов, поэтому я должен иметь забыл изменить это. Наконец, ** спасибо ** за указание на концепцию прямого возврата - это избавляет меня от множества хлопот и, надеюсь, я запомню это на будущее. – jwarner112

+0

Кроме того, я не понимаю «для NaN. ВНИМАНИЕ: для gcc вам нужно скомпилировать с -lm». А именно, термины «gcc» и «-lm». И, наконец, я не очень хорошо понимаю «переключатель». Вы говорите ему, чтобы перейти к любому из этих пяти случаев (включая 'default'), но я не могу понять, как он знает, какой случай использовать. Где это условие? Или числа, следующие за «случайными» номерами по совпадению, и мы фактически используем мой вход для выбора случая? (Извините, что у вас больше вопросов, которые пристают) – jwarner112

1

В вашем конкретном случае, было бы лучше использовать карту указателей на функции:

map<int,float (*)(float, float)> Operations; 
Operations.insert(pair<int,float (*)(float, float)>(1, Addition)); 
Operations.insert(pair<int,float (*)(float, float)>(2, Division)); 
Operations.insert(pair<int,float (*)(float, float)>(3, Multiplication)); 
Operations.insert(pair<int,float (*)(float, float)>(4, Subtraction)); 

Таким образом, вы можете просто вызвать функции, такие как

Operations[operatorSelection](0,1); 

P.S. в вашем коде мало опечаток - должно быть float result = вместо результата, может быть, другого ...

С точки зрения эффективности, однако, оператор switch(), вероятно, будет наиболее эффективным ...

+0

Я не уверен, что вы имеете в виду, когда указываете, что у меня опечатки; Не могли бы вы перефразировать его, может быть? – jwarner112

+0

Я имел в виду, что код не будет компилироваться, как вы его разместили, потому что он имеет синтаксические ошибки. Например, строка (result = firstNumber-secondNumber;) должна быть (float result = firstNumber-secondNumber;). Взгляните на ответ GT_mh, он предоставил рабочий пример вашего кода и уже прошел опечатки. –

+0

Спасибо, я читаю и пытаюсь понять его код сейчас; Забавно, как «результат» был совершенно лишним, как выясняется. – jwarner112

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