3
\$\begingroup\$

Part 2 of this question. I've rewritten most parts of the code, for the better I hope. The code now has some more logic and less readability.

Functions included in the calculator:

  • Addition
    User input 2+2 Program output 4

  • Subtraction
    User input 2-2 Program output 0

  • Multiplication
    User input 2*2 Program output 4

  • Division
    User input 2/2 Program output 1

  • Exponentiation
    User input 2^2 Program output 4

#include <iostream>
#include <string>
#include <sstream>
#include <Windows.h>
#include <cmath>

class Math_Functions
{
public:
    double addition(double, double);
    double subtraction(double, double);
    double multiplication(double, double);
    void division(double, double);
    void exponentiation(double, double);
} math;

class Results_Handler
{
public:
    void division(std::string);
    void exponentiation(std::string);
} res_handler;

//This function I found somewhere in the deep internet
class Miscellaneous
{
public:
    void Pause()
    {
        std::cout << std::endl << "Press any key to continue . . . ";
        std::cin.sync();
        std::cin.ignore();
    }
    void ClearScreen()
    {
        HANDLE                     hStdOut;
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        DWORD                      count;
        DWORD                      cellCount;
        COORD                      homeCoords = { 0, 0 };

        hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hStdOut == INVALID_HANDLE_VALUE) return;

        /* Get the number of cells in the current buffer */
        if (!GetConsoleScreenBufferInfo(hStdOut, &csbi)) return;
        cellCount = csbi.dwSize.X *csbi.dwSize.Y;

        /* Fill the entire buffer with spaces */
        if (!FillConsoleOutputCharacter(
            hStdOut,
            (TCHAR) ' ',
            cellCount,
            homeCoords,
            &count
            )) return;

        /* Fill the entire buffer with the current colors and attributes */
        if (!FillConsoleOutputAttribute(
            hStdOut,
            csbi.wAttributes,
            cellCount,
            homeCoords,
            &count
            )) return;

        /* Move the cursor home */
        SetConsoleCursorPosition(hStdOut, homeCoords);
    }
} misc;


//Handle the result from division and cout correspondingly
void Results_Handler::division(std::string inPut)
{
    if (inPut != "Error")
    {
        std::cout << inPut;
    }
    else
    {
        std::cout << "Come on, you know you can't divide by 0...";
    }
}

//Handle the result from the exponentiation and cout correspondingly
void Results_Handler::exponentiation(std::string inPut)
{
    if (inPut != "Error")
    {
        std::cout << inPut;
    }
    else
    {
        std::cout << "You can't exponentiate by negative numbers.";
    }
}

double Math_Functions::addition(double a, double b)
{
    return a + b;
}

double Math_Functions::subtraction(double a, double b)
{
    return a - b;
}

double Math_Functions::multiplication(double a, double b)
{
    return a * b;
}

void Math_Functions::division(double a, double b)
{
    //Dividing by 0 = universe explodes
    if (b == 0)
    {
        res_handler.division("Error");
    }
    else
    {
        double c = a / b;
        std::stringstream result;
        result << c;
        res_handler.division(result.str());
    }
}

void Math_Functions::exponentiation(double a, double b)
{
    //If the number you're exponentiating with is 0 the result is always 1
    if (b == 0)
    {
        res_handler.exponentiation("1");
    }
    //If you're exponentiating with 1 the result is the same number
    else if (b == 1)
    {
        std::stringstream res;
        res << a;
        res_handler.exponentiation(res.str());
    }
    else
    {
        std::stringstream res;
        res << pow(a, b);
        res_handler.exponentiation(res.str());
    }
}

int main()
{
    //Declare variables
    double a, b;
    char function;
    std::string line;

    while (true)
    {
        misc.ClearScreen();
        std::getline(std::cin, line);

        //Check if the input is empty and ignore
        if (line.empty())
        {
            continue;
        }
        //Check if the input is either 'q' or 'Q' and break loop
        else if (line[0] == 'q' || line[0] == 'Q')
        {
            break;
        }
        //Else if everything is OK extract data
        else
        {
            std::istringstream inStream(line);
            inStream >> a;
            inStream >> function;
            inStream >> b;

            //Check for bad input and print error
            if (!inStream || function != '+' && function != '-' && function != '*' &&     function != '/' && function != '^')
            {
                std::cerr << "\"" << line << "\" is invalid input";
            }
        }

        //Check what the user wants to do
        switch (function)
        {
        case '+': std::cout << math.addition(a, b); break;
        case '-': std::cout << math.subtraction(a, b); break;
        case '*': std::cout << math.multiplication(a, b); break;
        case '/': math.division(a, b); break;
        case '^': math.exponentiation(a, b); break;
        }
        misc.Pause();
    }
    return 0;
}
\$\endgroup\$
  • \$\begingroup\$ The request for a library is not on-topic here, nor is it anywhere on SE. You may just have to search for something yourself and try to implement it here. \$\endgroup\$ – Jamal Jan 20 '15 at 14:33
1
\$\begingroup\$

The singleton pattern:

Your classes Math_Functions, Results_Handler and Miscellaneous seem like an attempt at the singleton pattern (see 1 and 2). Your approach of declaring a global instance of each class is also valid, but has a few drawback and is not very conventional.

Since your classes hold no member data and the class is really just serving as a name space for the functions, I would use an actual namespace instead and don't even bother with a full-blown singleton implementation in this case. Example:

namespace math
{
    double addition(double, double);
    double subtraction(double, double);
    double multiplication(double, double);
    void division(double, double);
    void exponentiation(double, double);
} // namespace

Then to access each function you now have to use the :: (namespace resolution) operator: math::addition(a, b);

Miscellaneous tips:

  • Keep parameter names in function prototypes. This adds to the code documentation.

  • Be consistent with your naming convention. You have both PascalCase and camelCase names for functions/methods. Choose one and use it consistently.

  • Functions from <cmath>, such as pow(), should be accessed using the fully qualified name with the std:: prefix. I.e.: std::pow().

  • Consider splitting your project in a few separate source files. There is quite a bit of code here already to be kept all in the same source file. You should ideally place each class in its own .cpp/.h pair.

  • Returning zero at the end of main is optional. If you don't do it explicitly, the compiler will default to a return 0.

\$\endgroup\$
  • \$\begingroup\$ I really want to separate the code in different files, but the problem is I don't know how (yet). I can include other .cpp files in the main, but this way it doesn't make much sense to me. Thanks for the guidelines :) \$\endgroup\$ – skorpi7478 Jan 20 '15 at 17:52
  • \$\begingroup\$ @skorpi7478, Well, take a look at how to do that in your IDE/compiler. You will then have the class implementation in a .CPP file and the declaration in a header file (.H); Then you include the .H in your other sources files, such as in main.cpp. \$\endgroup\$ – glampert Jan 20 '15 at 18:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.