This is my first time using classes objects and functions. What can I improve on?
#include <iostream>
#include <conio.h>
using namespace std;
class functions{
public:
void Body(){
cout << " :: Welcome to Taylor's CALCULATOR! ::" << endl;
}
int Addition(int x, int y){
int ans = x + y;
return ans;
}
int Subtraction(int x, int y){
int ans = x - y;
return ans;
}
int Multiplication(int x, int y){
int ans = x * y;
return ans;
}
int Division(int x, int y){
int ans = x / y;
return ans;
}
};
int main(){
int func;
int x, y;
functions key; //Object
key.Body(); //Object
cout << "What function do you want to use? " << endl;
cout << "1 - Addition " << endl;
cout << "2 - Subtraction " << endl;
cout << "3 - Multiplication " << endl;
cout << "4 - Division " << endl;
cout << "Input: " << endl;
cin >> func;
cout << endl;
switch(func){
case 1: //Addition
cout << "**ADDITION**" << endl;
cout << "Please enter first number: " << endl;
cin >> x;
cout << "Please enter second number: " << endl;
cin >> y;
cout << x << " + " << y << " = ";
cout << key.Addition(x, y);
break;
case 2: //Subtraction
cout << "**SUBTRACTION**" << endl;
cout << "Please enter first number: " << endl;
cin >> x;
cout << "Please enter second number: " << endl;
cin >> y;
cout << x << " - " << y << " = ";
cout << key.Subtraction(x, y);
break;
case 3: //Multiplication
cout << "**MULTIPLICATION**" << endl;
cout << "Please enter first number: " << endl;
cin >> x;
cout << "Please enter second number: " << endl;
cin >> y;
cout << x << " x " << y << " = ";
cout << key.Multiplication(x, y);
break;
case 4: //Division
cout << "**DIVISION**" << endl;
cout << "Please enter first number: " << endl;
cin >> x;
cout << "Please enter second number: " << endl;
cin >> y;
cout << x << " / " << y << " = ";
cout << key.Division(x, y);
break;
default:
cout << "Invalid Input...";
break;
}
}
8 Answers 8
Unless you'll be maintaining an accumulated number for multiple operations, this may not be the best use of classes. For your code, you'd get the same effect by just performing these calculations within the switch
statement (something similar to this). Right now, you're just using a class to contain similar functions, including a trivial output function.
Some additional notes:
- Try not to use
using namespace std
. - Indent everything within
main()
as well. Not doing so may make it hard to tell that the code is being contained within something. - You don't need
<conio.h>
here, so just remove it. - It may be useful to prevent the user from dividing by 0, which is undefined behavior.
Repetitive block of code:
cout << "Please enter first number: " << endl;
cin >> x;
cout << "Please enter second number: " << endl;
cin >> y;
Move it outside switch or to another method. e.g. getNumbers(int& x, int& y)
You don't need to store the answer, just return the results:
return x+y;
return x-y;
etc ...
I'm aware it's just a learning example but to be honest the usage of class object here is completely pointless.
There is nothing shared between your operations that could justify the object creation.
-
\$\begingroup\$ there's one thing shared - use semantics of the methods; IMO he could (or rather, should) turn those methods static, and treat this class as an utility one. Otherwise, I wholeheartedly agree. \$\endgroup\$user20300– user203002016年11月10日 21:26:46 +00:00Commented Nov 10, 2016 at 21:26
-
\$\begingroup\$ Then it should be rather a namespace, not a class full of static methods. Less typing and less confusion. \$\endgroup\$woockashek– woockashek2016年11月10日 21:31:43 +00:00Commented Nov 10, 2016 at 21:31
-
\$\begingroup\$ not necessarily; there's a distinct difference between the usual use of namespaces and the usual use of Utility Class pattern - in most real-life situations I've seen, C++ namespace is a "top level" container (e.g. one namespace for a piece of software), similar to e.g. package in Java or namespace in C#; as such, e.g., you'd have
namespace mathtools { class Calculator {} }
; I'm not saying it's the best choice in this particular case, but a) it's a tutorial program, so it should, well, tutor, b) it's the general rule of thumb for actual software I've seen. \$\endgroup\$user20300– user203002016年11月10日 21:42:37 +00:00Commented Nov 10, 2016 at 21:42
The first thing I notice is that you ask for numbers 1 and 2 in every case statement. You know will always need two numbers, why not move that outside and code it once?
Others have already pointed out that this is a contrived example, but no one has mentioned this angle (which actually prompted me to make my first post here...)
For me it's a bit "brittle" because your main's menu is linked to the operations in the class. If you modify the functions
class to add some more operations you also have to modify main()
to put them in the menu and get the parameters to pass through.
One approach would be to let functions
print the menu - but then it also needs to map responses to functions, so then you might say make it get the parameters as well, so you run the risk of creating a "ball of mud".
I'm still on the C++ learning curve but a few things I would change here is:
Read
x
andy
only once (using C style):int x, y; scanf("%d %d", &x, &y);
or
int x, y; cin >> x; cin >> y;
You can call any operation on these values.
Rather than switch with 1, 2 ... I would switch on characters e.g. +, - , *, / etc.
I would change the class name to
calculator
as opposed tofunctions
.
-
2\$\begingroup\$ scanf in c++? I'd advocate against it. The proposed name
calculator
is very misleading without also pulling logic into the class, it's more like anamespace math
right now \$\endgroup\$WorldSEnder– WorldSEnder2016年11月10日 01:40:42 +00:00Commented Nov 10, 2016 at 1:40 -
\$\begingroup\$ @WorldSEnder scanf is a C style. I will update my answer \$\endgroup\$Tolani– Tolani2016年11月10日 10:13:20 +00:00Commented Nov 10, 2016 at 10:13
In addition to what Jamal said:
- Always check whether
std::cin >> x
succeeds. - Don't output trailing spaces before a line break, they are useless.
For the remaining issues you can pick any beginner C++ question here, the answers are almost always the same.
In fact you can basically get rid of the switch block altogether, by using a map to store a pointer the appropriate function with the character of the operation as the key. Now if you make the menu choice the operation characters, just get the 2 operands and run the appropriate function. Here's a little snippet that demonstrates how to set up and use the map:
#include <iostream>
#include <map>
using namespace std;
typedef double(*OperatorFunction)(double a, double b);
typedef map<char, OperatorFunction> op_functions;
double AddFunction(double a, double b)
{
//Add code here
}
double MinusFunction(double a, double b)
{
//Add code here
}
double TimesFunction(double a, double b)
{
//Add code here
}
double DivideFunction(double a, double b)
{
//Add code here
}
int main()
{
op_functions calcs;
calcs['+']= &AddFunction;
calcs['-']= &MinusFunction;
calcs['*']= &TimesFunction;
calcs['/'], &DivideFunction;
cout << calcs['+'](6, 8);
return 0;
}
-
1\$\begingroup\$ -1 is a valid answer, why are you returning it for divide by zero? \$\endgroup\$forsvarir– forsvarir2016年11月10日 08:37:22 +00:00Commented Nov 10, 2016 at 8:37
-
\$\begingroup\$ @forsvarir - The code I copied this from used that as an error code. It can easily be changed to throw an exception instead or trapped before the function is used. Either way the concept being demonstrated is valid. \$\endgroup\$user33306– user333062016年11月10日 08:45:42 +00:00Commented Nov 10, 2016 at 8:45
-
\$\begingroup\$ Since some people don't have enough intelligence to read the answer and see that the purpose isn't to deliver perfect functions but to demonstrated a concept, none of the functions have bodies. \$\endgroup\$user33306– user333062016年11月10日 20:41:10 +00:00Commented Nov 10, 2016 at 20:41
-
\$\begingroup\$ By the way, no need to define those (boring) functions yourself. Just use std::plus etc. which are already defined. In general, I like your answer. \$\endgroup\$Juho– Juho2016年11月12日 15:58:05 +00:00Commented Nov 12, 2016 at 15:58
There are some good answers here. My two cents, keeping my suggestions small and simple regarding the class is:
class Calculator{ //Classes start with capital letters.
public:
void message(){//'Body' is vague, 'message' isn't.
std::cout << " :: Welcome to Taylor's CALCULATOR! ::" << std::endl;
}
double addition(const double & x, const double & y){ //Pass by reference to reduce copies.
return x + y; // No need to creat new variables, just return a result.
}
double subtraction(const double & x, const double & y){ //No need to capitalize methods of a class.
return x-y;
}
double multiplication(const double & x, const double & y){ //Passed values aren't mutable, so declare them const.
return x * y;
}
double division(const double & x, const double & y){ //Return values are mutable, so don't declare them const.
if(y==0){
std::cout << "There was a divide-by-zero error in the division function.\n Don't divide by zero please." << std::end;
return 0;
}
return x / y;
}
};
Double may be better suited in case a result requires floating point.
-
2\$\begingroup\$ An int is a basic type, that is typically the same size as a reference, what is it you are gaining with this approach? Is recommending returning a fixed random answer rather than throwing an exception for divide by zero really setting the beginner off in a good direction? \$\endgroup\$forsvarir– forsvarir2016年11月10日 08:34:41 +00:00Commented Nov 10, 2016 at 8:34
-
1\$\begingroup\$ Its a very bad suggestion to return -1337. If one is not handling this case then it's better having no test for y=0 here as that will give the much more sensible results Inf or NaN when y=0. \$\endgroup\$Winther– Winther2016年11月10日 12:31:10 +00:00Commented Nov 10, 2016 at 12:31
-
\$\begingroup\$ Welcome to Code Review! As the other comments already mention I'm also doubtful about the advice and formatting; otherwise your answer looks fine, enjoy your stay! \$\endgroup\$ferada– ferada2016年11月10日 13:14:16 +00:00Commented Nov 10, 2016 at 13:14
-
1\$\begingroup\$ @Winther Good luck storing NaN or Inf in an
int
. \$\endgroup\$Sanchises– Sanchises2016年11月10日 13:49:58 +00:00Commented Nov 10, 2016 at 13:49 -
1\$\begingroup\$ Based on feedback, I've made corrections :) \$\endgroup\$NonCreature0714– NonCreature07142016年11月19日 01:38:11 +00:00Commented Nov 19, 2016 at 1:38
Explore related questions
See similar questions with these tags.
Addition(x,y)
method versus just writingx+y
in the code itself. If you want to boil this down, the answer would be "don't reinvent the wheel" and to just usex+y
,x-y
, etc in the switch. \$\endgroup\$