0

I'm writing an ATM object-oriented project in C++. I found an implementation in C# here, which I used: PDF file with implementation. I was trying to convert this project into C++ and build it in Code::Blocks. Currently I'm trying to debug the project but I get a lot of errors. I managed to solve some of them, but new ones still show up. Currently I'm stuck on something and I can't find an answer that would help me, maybe someone could explain to me what's going on here. Here's the code of the object which the error refers to:

`

ATM::ATM() 
{
    userAuthenticated = false;
    currentAccountNumber = 0;
    Screen screen;
    Keypad keypad;
    CashDispenser cashDispenser;
    DepositSlot depositSlot;
    BankDatabase bankDatabase;
}

void ATM::Run()
{
    while(true) 
    {
        while(!userAuthenticated)
        {
            screen.DisplayMessage("Welcome!\n");
            AuthenticateUser();
        }

        PerformTransactions();
        userAuthenticated = false;
        currentAccountNumber = 0;
        screen.DisplayMessage("\nThank you! Goodbye!\n");
    }
}

void ATM::AuthenticateUser()
{
    screen.DisplayMessage("\nPlease enter your account number: ");
    int accountNumber = keypad.GetInput();

    screen.DisplayMessage("\nPlease enter your PIN number: ");
    int pin = keypad.GetInput();

    userAuthenticated = bankDatabase.AuthenticateUser(accountNumber, pin);

    if (userAuthenticated)
        currentAccountNumber = accountNumber;
    else
        screen.DisplayMessage("Invalid account number or PIN, please try again.\n");
}

void ATM::PerformTransactions()
{
    Transaction currentTransaction;
    bool userExited = false;

    while (!userExited)
    {
        int mainMenuSelection = ATM::DisplayMenu();

        switch((MenuOption)mainMenuSelection)
        {
        case BALANCE_INQUIRY: dzialalo
        case WITHDRAWAL:
        case DEPOSIT:
            currentTransaction = CreateTransaction(mainMenuSelection);
            currentTransaction.Execute();
            break;
        case EXIT_ATM:
            screen.DisplayMessage("Exiting the system\n");
            userExited = true;
            break;
        default:
            screen.DisplayMessage("Wrong input, try again\n");
            break;

        }
    }
}

int ATM::DisplayMenu()
{
    screen.DisplayMessage("\nMain menu: \n1. - View balance \n2. - Withdraw cash \n3. - Deposit cash \n4. - Exit \nEnter a number:\n");
    return keypad.GetInput();
}


Transaction ATM::CreateTransaction(int type)
{

    switch((MenuOption)type)
    {
    case BALANCE_INQUIRY: //MenuOption.BALANCE_INQUIRY gdyby nie dzialalo
        BalanceInquiry temp(currentAccountNumber,screen,bankDatabase);
        break;
    case WITHDRAWAL:
        Withdrawal temp(currentAccountNumber,screen,bankDatabase,keypad,cashDispenser);
        break;
    case DEPOSIT:
        Deposit temp(currentAccountNumber,screen,bankDatabase,keypad,depositSlot);
        break;
    }
    return temp;
}

`

I get this error when I try to run whole project: ERRORS I GET

Is the compiler telling me, that in function ATM::PerformTransactions() the object that I'm trying to create is a function? How is it possible? Isn't it possible to create an object like that? Transaction currentTransactionCan someone tell me what's wrong? I'd really appreciate your help.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
user3524911
  • 13
  • 1
  • 3
  • 1
    The error message is clear: there is no default constructor. You probably want dynamic object creation, not static. Pointers. – Sami Kuhmonen Sep 10 '16 at 19:41
  • 1
    The real problem is assuming that C++ works the same as C# and using C# as a model in writing C++ code, if not just plain "winging it" and hoping for no compiler errors. For example, that `CreateTransaction` is not the way it would be written by a C++ programmer. If it did compile, it suffers from an object slicing issue. – PaulMcKenzie Sep 10 '16 at 19:48

2 Answers2

0

Unfortunately, it's hard to say exactly what the problem is, for this is far from being a minimal, complete and verifiable example.

That said, the error is probably in this function:

Transaction ATM::CreateTransaction(int type) {
    switch((MenuOption)type) {
    case BALANCE_INQUIRY:
        BalanceInquiry temp(currentAccountNumber,screen,bankDatabase);
        break;
    case WITHDRAWAL:
        Withdrawal temp(currentAccountNumber,screen,bankDatabase,keypad,cashDispenser);
        break;
    case DEPOSIT:
        Deposit temp(currentAccountNumber,screen,bankDatabase,keypad,depositSlot);
        break;
    }

    return temp;
}

It should be something like:

Transaction* ATM::CreateTransaction(int type) {
    switch((MenuOption)type) {
    case BALANCE_INQUIRY:
        return new BalanceInquiry(currentAccountNumber,screen,bankDatabase);
    case WITHDRAWAL:
        return new Withdrawal(currentAccountNumber,screen,bankDatabase,keypad,cashDispenser);
    case DEPOSIT:
        return new Deposit(currentAccountNumber,screen,bankDatabase,keypad,depositSlot);
    }
}

Or the more C++14-ish:

std::unique_ptr<Transaction> ATM::CreateTransaction(int type) {
    switch((MenuOption)type) {
    case BALANCE_INQUIRY:
        return std::make_unique<BalanceInquiry>(currentAccountNumber,screen,bankDatabase);
    case WITHDRAWAL:
        return std::make_unique<Withdrawal>(currentAccountNumber,screen,bankDatabase,keypad,cashDispenser);
    case DEPOSIT:
        return std::make_unique<Deposit>(currentAccountNumber,screen,bankDatabase,keypad,depositSlot);
    }
}

Admitted that BalanceInquiry, Withdrawal and Deposit inherit Transaction, of course

In the original code there where a few errors, first of all the fact that it would have given place to sliced object if it had worked.
For the question is not about slicing, I'd rather suggest to search on SO for further details.

Community
  • 1
  • 1
skypjack
  • 49,335
  • 19
  • 95
  • 187
0

The declaration of currentTransaction calls the default constructor

void ATM::PerformTransactions()
{
    Transaction currentTransaction;
    ...
}

that is automatically generated by the compiler in many cases. In your case the default constructor of Transaction cannot be automatically generated - maybe a field of the Transaction class has no default constructor.

So either you implement such a default constructor for Transaction calling adequate constructors for its fields, or you provide no default constructor and you use dynamic allocation:

void ATM::PerformTransactions()
{
    std::unique_ptr<Transaction> currentTransaction;
    bool userExited = false;

    while (!userExited)
    {
        int mainMenuSelection = ATM::DisplayMenu();
        switch((MenuOption)mainMenuSelection)
        {
        case DEPOSIT:
            currentTransaction = CreateTransaction(mainMenuSelection);
            currentTransaction->Execute();
            break;
          ...
        }
    }
}

with the following changes in the signature of CreateTransaction.

std::unique_ptr<Transaction>
ATM::CreateTransaction(int type) {
    std::unique_ptr<Transaction> result;
    switch((MenuOption)type) {
    case BALANCE_INQUIRY:
        result.reset(new BalanceInquiry(currentAccountNumber,screen,bankDatabase));
        break;
    case WITHDRAWAL:
        result.reset(new Withdrawal(currentAccountNumber,screen,bankDatabase,keypad,cashDispenser));
        break;
    case DEPOSIT:
        result.reset(new Deposit(currentAccountNumber,screen,bankDatabase,keypad,depositSlot));
        break;
    }

    return result;
}
Franck
  • 1,635
  • 1
  • 8
  • 11