The problem asks you to take an integer (debit amount) and a double (credit or initial balance amount) and process the requested debit verifying that 1 it's a multiple of the minimum denomimation amount of $5 and that it's also smaller than the credit/balance.  If either is untrue, it is supposed to return the initial deposit amount otherwise it will return the new balance.Full problem descriptionI have created 3 objects for this problem:Transaction - This object reads in the two initial values given and then is used in ATMATM - Takes the transaction and applies them to the account and then displays the new balance.Account - This object keeps track of the current account balance and updates the balance if the ATM passes it a value.Limitations:I understand that it can only process a single account, but that is more a limitation set by the problem description than it is me not accounting for multiple accounts.  Also no error is returned if the balance cannot be updated, but it is not a requirement.  I also understand I made a mountain out of a molehill with this problem as it can be solved by much less code.In what ways can I improve this code other than the limitations mentioned?#include <istream>#include <iostream>#include <iomanip>class Account {public:    Account()         :   mBalance(0.0)    {}    void updateBalance(double transaction) {        mBalance += transaction;    }    double getBalance() {        return mBalance;    }private:    double mBalance;};class Transaction {public:    Transaction()         :   mDebit(0)        ,   mCredit(0.0)    {}    int getDebit() {        return mDebit;    }    double getCredit() {        return mCredit;    }    friend std::istream& operator>>(std::istream& input, Transaction& transaction) {        input >> transaction.mDebit;        input >> transaction.mCredit;        return input;    }private:    int     mDebit;    double  mCredit;};class ATM {public:    ATM()         :   mAccount()        ,   mMinDenomination(5)        ,   kWithdrawal_fee(0.50)    {}    void processTransaction(Transaction& transaction) {        credit(transaction);        debit(transaction);    }    void displayBalance() {         std::cout << mAccount.getBalance() << '\n';    }private:    Account             mAccount;    int                 mMinDenomination;    const double        kWithdrawal_fee;    bool debit(Transaction& transaction) {              if(isWithdrawable(transaction.getDebit())){                     mAccount.updateBalance(-1*(transaction.getDebit() + kWithdrawal_fee));            return true;        }        return false;    }    void credit(Transaction& transaction) {        if(transaction.getCredit() > 0) {            mAccount.updateBalance(transaction.getCredit());         }    }    bool isWithdrawable(int transaction) {        if(transaction % mMinDenomination == 0) {            return mAccount.getBalance() >= transaction + kWithdrawal_fee;        }        return false;    }};int main() {    std::iostream::sync_with_stdio(false);    std::cout << std::setprecision(2) << std::fixed;    Transaction transaction;    ATM         atm;        std::cin >> transaction;        atm.processTransaction(transaction);    atm.displayBalance();    return 0;}
Clean code attempt at ATM problem on codechef.com
c++;beginner;c++11;programming challenge;finance
Design.You use a mixture of int and doubles to represent monatary units. This is not a good idea. double (like all fixed with decimal representations, can not hold all values exactly). You should use an integer like type (where all values are represented exactly). If you are in America and using dollars and cents then I would use an integer but the balance of the account is held in cent. When you print it out you can then place the decimal point in the correct place.Code ReviewIn:class Account {I always think getters are wrong. They break encapsulation. Looking forward in your code you use them for two reasons. 1) Printing. 2) To test if the account has enough funds for withdraw. In both cases you should add explicit methods.    double getBalance() {        return mBalance;    }I would replace the above with:    friend std::ostream& operator<<(std::ostream& s, Account const& data)    {        // Assuming you changed (as suggested above to hold account balance in cent.        s << $ << data.mBalance / 100 << . << data.mBalance % 100;    }    virtual bool canWithdraw(double amount)    {          return mBalance > amount;    }This logic protects you against future improvements to the system. What happens if you add the ability of some accounts to go overdrawn (for a fee). Then in your code you have to find all locations where the balance is being checked and modify those. In the method I propose you only need to modify one place (the Account class). You have localized the test for whether the account can withdraw money.In:A debit is an integer and a credit is a double.I don't understand the logic here.    int     mDebit;    double  mCredit;They should be the same. If you have some compelling reason for the difference then I need a big comment about why they are different (you may have a good reason, but you will need to explain it in the code).Personally I would just have an amount. A negative amount is a debt and positive amount a credit.Getters. Ahhh. horrible.    int getDebit() {        return mDebit;    }    double getCredit() {        return mCredit;    }Again the only use is do tests and fiddling that should be part of the Accounts responsibility. You should send the transaction to the account which may reject the transaction if it fails any of the account specific validations (ie you can have a negative balance).Like this.    friend std::istream& operator>>(std::istream& input, Transaction& transaction) {        input >> transaction.mDebit;        input >> transaction.mCredit;        return input;    }But usually when you have an input stream reader you also have an output stream writer that mirrors the reader. So when you persist to a stream the class can also read the value in.In ATM:Interesting. You have a debit action and credit action applied for every transaction. Does this mean that a transaction can perform both operations?    void processTransaction(Transaction& transaction) {        credit(transaction);        debit(transaction);    }Its OK to have a print method().    void displayBalance() {         std::cout << mAccount.getBalance() << '\n';    }But usually it is best for this to just call the stream operator.    void displayBalance() {         std::cout << mAccount; // The account should know how to serialize itself.    }This shows how bad an idea it is to have functions that have success state.    bool debit(Transaction& transaction) {              if(isWithdrawable(transaction.getDebit())){                     mAccount.updateBalance(-1*(transaction.getDebit() + kWithdrawal_fee));            return true;        }        return false;    }You do it all correctly yet it is still broken. Because the calling code does not check the return value. Yes internally within a class it is absolutely fine to return status codes (because you do not expose the interface publicly). But you must also make sure you do actually test the result codes.Note: It is never (very rarely) OK to expose status codes that need checking publicly. As we can see in the C world (were this practice is the norm)it is so easy to not check the error codes and thus invalidate any following code. You should write code so it can not be used incorrectly which means forcing your users to do the correct thing (or the program exits (exceptions)).