I am trying to make a program that has two account balances, one for a go-card the other for a bank account. I have made a class for each, however when I try to call the debit method in the go-card class via a class pointer, my program crashes (it compiles with no errors).
The GoCardAccount.cpp file:
#include <cstdio>
#include "GoCardAccount.hpp"
#include "BankAccount.hpp"
GoCardAccount::GoCardAccount(long initialamount, BankAccount(ba)) {
balance = initialamount;
}
bool GoCardAccount::trip(long amount) {
LOW_LIMIT = 1000;
TOP_UP = 5000;
if(balance >= amount) {
balance -= amount;
if(balance < LOW_LIMIT) {
if(ba->debit(TOP_UP)) {
printf("Balance fallen below minimum, "
"topped up $50 to go card account.\n");
balance += TOP_UP;
return true;
}
else {
printf("Your balance has gone below minimum amount, however "
"there are insufficient funds in bank account to top up.\n");
return true;
}
}
}
else {
return false;
}
}
long GoCardAccount::getBalance() {
return balance;
}
GoCardAccount.hpp file:
class BankAccount;
class GoCardAccount {
long balance;
BankAccount *ba;
long LOW_LIMIT;
long TOP_UP;
public:
GoCardAccount(long amount, BankAccount(ba));
bool trip(long amount);
long getBalance();
};
The debit method from BankAccount.cpp:
bool BankAccount::debit(long amount1) {
if(amount1 >=0 && amount1 <= balance) {
balance -= amount1;
return true;
}
else {
return false;
}
}
The start of the main function where I initialise the classes:
int main(void) {
long startamount;
long gocardamount;
printf("Input initial bank balance: \n");
scanf("%ld", &startamount);
BankAccount ba(startamount);
printf("Input initial Go-Card balance: \n");
scanf("%ld", &gocardamount);
GoCardAccount gca(gocardamount, ba);
}
For first let's talk about your constructor of class GoCardAccount, because there is a term used by Scott Meyers in Effective STL (2001) book, which is the most vexing parse:
GoCardAccount(long amount, BankAccount(ba));
The code snippet above will declare a constructor which takes two parameters:
The long amount parameter is named amount, and it's type is long. This is fine.
The BankAccount(ba) parameter is named ba, and it's type is BankAccount, because the parentheses around ba are superfluous and are ignored.
So, the declaration above is same as:
GoCardAccount(long amount, BankAccount ba);
This isn't what you want, because the second parameter will take a BankAccount instance by value and you need a pointer to it. So, you have to change it to:
GoCardAccount(long amount, BankAccount* ba);
Change its definition as well and initialize your BankAccount* ba member as follows (or use the member initializer list):
GoCardAccount::GoCardAccount(long initialamount, BankAccount* ba_ptr) {
balance = initialamount;
ba = ba_ptr;
}
Now you are trying to call ba method, but BankAccount *ba; is not even itinialized.
You have to pass a pointer on BankAccount to GoCardAccount ctor. So change this line (in main)
GoCardAccount gca(gocardamount, ba);
to
GoCardAccount gca(gocardamount, &ba);
and in GoCardAccount (GoCardAccount.cpp) change ctor from
GoCardAccount::GoCardAccount(long initialamount, BankAccount(ba))
{
balance = initialamount;
}
to
GoCardAccount::GoCardAccount(long initialamount, BankAccount * pba) :
balance (initialamount), ba(pba) {}
The argument
BankAccount(ba)
won't store argument passed to ctor to ba, it means that argument passed in function call, which will be placed on stack, will has identifier ba.
You should use different name than member variable
It has to be pointer (in your case)
In member initialize list you have to assign this value to member variable
Example
GoCardAccount::GoCardAccount(long initialamount, BankAccount * pba) : balance (initialamount), ba(pba) {}
Related
all! This is my first post, so please be gentle.
My code is meant to simulate a rudimentary version of transferring money from one bank account to another. My code is as follows:
#include <cstdio>
struct Account
{
virtual ~Account() {}
virtual double get_balance() = 0;
virtual double set_balance(double amount) = 0;
virtual Account* transfer_balance(Account* to, double amount) = 0;
long account_id;
double balance;
unsigned int privileges;
};
struct UserAccount : Account
{
UserAccount(long account_id): account_id{account_id} {
printf("Account %ld initialized at %p\n", account_id, this);
};
double get_balance() override
{
return balance;
}
double set_balance(double amount) override
{
this->balance = amount;
return balance;
}
Account* transfer_balance(Account* to, double amount) override
{
to->set_balance(to->get_balance() + amount);
this->set_balance(this->get_balance() - amount);
return to;
}
long account_id;
double balance
{ 0 };
unsigned int privileges;
};
int main()
{
UserAccount test_acct_one(23);
UserAccount test_acct_two(98);
test_acct_one.transfer_balance(&test_acct_two, 200);
printf("Balance of Account %ld: %lG\n", test_acct_one.account_id, test_acct_one.get_balance());
printf("Balance of Account %ld: %lG\n", test_acct_two.account_id, test_acct_two.get_balance());
}
Output:
Account 23 initialized at 0x7fff8e927a40
Account 98 initialized at 0x7fff8e927a00
Balance of Account 23: -200
Balance of Account 98: 200
While this code works, it feels a bit finicky to transfer the values like this:
to->set_balance(to->get_balance() + amount);
this->set_balance(this->get_balance() - amount);
However, when I try to do this:
to->balance += amount;
balance -= amount;
The output turns into:
Account 23 initialized at 0x7ffc37b91a40
Account 98 initialized at 0x7ffc37b91a00
Balance of Account 23: -200
Balance of Account 98: 0
As you can see, while Account 23's (the first one's) balance is properly set to -200, Account 98's (the second one's) balance neither increases nor decreases, and I can't understand why. Some explanation of this behavior would be much appreciated.
You've duplicated all your member variables in both types. When you attempt to modify balance directly, it's trying to modify Account::balance, but set_balance and get_balance will use UserAccount::balance since that's available in the scope where the virtual is implemented.
Your UserAccount class has a balance member and is derived from the Account class which also has a balance member. When you access the balance through the virtual functions in Account, it changes UserAccount::balance. But when you increment the member variable directly with to->balance += amount, it's Account::balance which is used because to is a pointer to Account.
Decide whether you really need to user virtual functions. (I don't see that you do.) If you keep them, remove the variables from Account and access the balance through virtual functions. If you decide to remove the virtual functions, you really only need one class so it's pretty obvious which number you're incrementing.
struct UserAccount
{
UserAccount(long account_id): account_id{account_id} {
printf("Account %ld initialized at %p\n", account_id, this);
};
double get_balance()
{
return balance;
}
double set_balance(double amount)
{
this->balance = amount;
return balance;
}
UserAccount* transfer_balance(UserAccount* to, double amount)
{
to->balance += amount;
balance -= amount;
return to;
}
long account_id;
double balance
{ 0 };
unsigned int privileges;
};
So I have an assignment due in my C++ class on classes, and I'm having some trouble. Here is the description of the assignment:
Programming Challenge 7 on page 499 of your text asks you to design and Inventory Class that can hold information for an item in a retail store's inventory. You are given the code for the creation of the class along with code for the implementation of the functions. Demonstrate the class by writing a simple program that uses it. This program should demonstrate that each function works correctly. Submit your .cpp file using the link provided.
And here are the contents of the file sent (it's quite lengthy):
// Chapter 7---Files for Programming Challenge 13---Inventory Class
// This is the inventory.h file.
// It contains the Inventory class declaration.
#ifndef INVENTORY_H
#define INVENTORY_H
class Inventory
{
private:
int itemNumber;
int quantity;
double cost;
double totalCost;
public:
// Default constructor
Inventory()
{ itemNumber = quantity = cost = totalCost = 0; }
// Overloaded constructor
Inventory(int, int, double); // Defined in Inventory.cpp
// Mutators (i.e., "set" functions) defined in Inventory.cpp
void setItemNumber(int);
void setQuantity(int);
void setCost(double);
// setTotalCost calculates the total cost
// and stores the result in the totalCost member
void setTotalCost()
{ totalCost = cost * quantity; }
// Accessors (i.e., "get" functions)
int getItemNumber()
{ return itemNumber; }
int getQuantity()
{ return quantity; }
double getCost()
{ return cost; }
double getTotalCost()
{ return totalCost; }
// Input validation functions
bool validInt(int);
bool validFloat(double);
};
#endif
// This is the inventory.cpp file.
// It contains the Inventory class function definitions.
#include <iostream>
#include "Inventory.h"
using namespace std;
//************************************************************
// Overloaded constructor
// Accepts arguments to be stored in each member variable.
//************************************************************
Inventory::Inventory(int in, int q, double c)
{
setItemNumber(in);
setQuantity(q);
setCost(c);
setTotalCost();
}
//************************************************************
// setItemNumber accepts an argument to be stored in item number.
//************************************************************
void Inventory::setItemNumber(int in)
{
while (!validInt(in))
{
cout << "Item Number must be positive. Please re-enter: ";
cin >> in;
}
itemNumber = in;
}
//************************************************************
// setQuantity accepts an argument to be stored in quantity.
//************************************************************
void Inventory::setQuantity(int q)
{
while (!validInt(q))
{
cout << "Quantity must be positive. Please re-enter: ";
cin >> q;
}
quantity = q;
}
//************************************************************
// setCost accepts an argument to be stored in cost.
//************************************************************
void Inventory::setCost(double c)
{
while (!validInt(c))
{
cout << "Cost must be positive. Please re-enter: ";
cin >> c;
}
cost = c;
}
//************************************************************
// The validInt member tests its integer argument to see
// if it is negative. If the argument is negative, the function
// returns false. Otherwise, the function returns true.
//************************************************************
bool Inventory::validInt(int value)
{
if (value < 0) // the value is negative so it is NOT valid
return false;
else // the integer value is valid
return true;
}
//************************************************************
// The validFloat member tests its floating-point argument to see
// if it is negative. If the argument is negative, the function
// returns false. Otherwise, the function returns true.
//************************************************************
bool Inventory::validFloat(double value)
{
if (value < 0) // the value is negative so it is NOT valid
return false;
else // the floating-point value is valid
return true;
}
I'm just not sure how to use this information to make a program that demonstrates the class, and it could be as simple as me not saving the file the correct way
Just write a main function which instantiates an Inventory object and calls each of its methods in a meaningful way. This isn't a puzzle, just find a way to call the functions that makes sense to you.
I know this question has already been asked, but none of the answers that I have as of yet found seem to suffice. I am creating a vector of pointers to a base class and adding all sorts of derived classes to it. Now, the base class has a virtual function that is overridden in all of the derived classes and that is unique to each of them. So, when I go through the vector and retrieve those objects and call the function on that object, I need it to call the right one, but all it will do is call the base class version. I am even trying to cast the individual elements back to their original class when I retrieve them from the vector but they refuse to be cast! e.g.
vector<base*> myBase;
DerivedClass *myDerived = static_cast<DerivedClass> myBase[i];
This doesn't work, despite the fact that everything I've read suggests that it should. My debugger says that despite all of this, myDerived is still of type base and it's version of my virtual function is being called.
Any ideas?
class BankAccount {
public:
BankAccount(string namein, string typein){
name = namein;
type = typein;
balance = 0;
}
virtual string getType();
virtual void printTransactions() = 0;
virtual int withdraw(double amt){
return getBalance() -amt;
}
};
class SavingsAccount: public BankAccount {
public:
SavingsAccount(string namein, string typein);
void addTransaction(string transType, string name);
virtual int withdraw(double amt);
void printTransactions();
virtual string getType();
private:
};
SavingsAccount::SavingsAccount(string namein, string typein): BankAccount(namein, typein) {
}
int SavingsAccount::withdraw(double amt){
double aBal = getBalance() - amt;
if (aBal > 0){
setBalance(aBal);
}
return getBalance() - amt;
}
class CheckingAccount: public SavingsAccount {
public:
CheckingAccount(string nameIn, string typein): SavingsAccount(nameIn, typein){
}
virtual int withdraw(double amt);
void printTransactions();
string getType(){
return "Checking";
}
};
int CheckingAccount::withdraw(double amtIn){
double newBal = getBalance() - amtIn;
if (newBal < 500.00 && newBal > 2.49) {
setBalance(newBal - 2.50);
}
return newBal;
}
int main(int argc, const char * argv[])
{
vector<BankAccount*> myAccts;
SavingsAccount *mySav;
CD *myCD;
CheckingAccount *myCheck;
switch (option) {
case 1: {
string name;
string type;
cout << "Enter name: ";
cin >> name;
getline(cin, dump);
cout << "Enter account type: ";
cin >> type;
getline(cin, dump);
if (type.compare("Checking") == 0) {
CheckingAccount myCheck1 = CheckingAccount(name, type);
myAccts.push_back(&myCheck1);
}
case 3:{
for (int x = 0; x < myAccts.size(); x++) {
if (myAccts[x]->getName() == name && myAccts[x]->getType() == type) {
if (type == "Savings") {
mySav = static_cast<SavingsAccount*>(myAccts[x]);
double y = mySav->withdraw(amt);
if (y < 0){
cout << "Insufficient funds!";
}
}
if (type == "Checking") {
myCheck = myAccts[x]->GetDerived();
double y = myCheck->withdraw(amt);
if (y < 0){
cout << "Insufficient funds!";
}
if (y < 497.5) {
cout << "Withdrawal fee: $ 2.50" << endl;
}
}
}
Checking Account is a child of Savings Account. Sorry.
Your concept is correct and shouldn't require any casting. The whole point of virtual functions is that if you're holding a base class pointer or reference and call a virtual function, the most derived version of this function will be called at runtime.
The error I see is this:
if (type.compare("Checking") == 0) {
CheckingAccount myCheck1 = CheckingAccount(name, type);
myAccts.push_back(&myCheck1);
You are creating a checking account on the stack, then taking it's address and pushing that address into the vector. At the end of the if block myCheck1 will go out of scope and be destroyed. Your vector will have an address to a location in the stack and you will have Undefined Behavior.
Instead do:
if (type.compare("Checking") == 0) {
myAccts.push_back(new CheckingAccount(name, type));
And similar for the other types. Get rid of all of those casts. In this version you will have to delete all of the items in the vector at the end. If you use a std::vector<std::unique_ptr<BankAccount>> then the unique_ptr will take care of cleaning up your allocated objects.
You need to use new to create your accounts... you have:
if (...)
{
CheckingAccount myCheck1 = CheckingAccount(name, type);
myAccts.push_back(&myCheck1);
}
...myCheck1 gets destroyed when leaving that if scope, leaving myAccts with a pointer to an effectively random location on the stack that has undefined behaviour if accessed. Change to:
if (type == "Checking")
myAccts.push_back(new CheckingAccount(name, type));
You will then need to have matching deletes for the vector elements. Googling "C++ new delete tutorial" would be a good idea. The next stage is to learn how to use smart pointers, for example - std::shared_pointer - which remove the burden of remembering to delete.
"Case 3" can be corrected/simplified to:
for (int x = 0; x < myAccts.size(); x++)
if (myAccts[x]->getName() == name && myAccts[x]->getType() == type) {
double y = myAccts[x]->withdraw(amt);
if (y < 0)
cout << "Insufficient funds!";
if (type == "Checking" && y < 497.5)
cout << "Withdrawal fee: $ 2.50" << endl;
}
Notice in particular the double y = myAccts[x]->withdraw(amt); - the virtual function makes sure the right version is called without you having to do anything type-specific in the calling code.
Have you tried something like this?
class base
{
public:
inline DerivedClass *GetDerived() {return (DerivedClass*)this;}
...
};
DerivedClass *myDerived = myBase[i]->GetDerived();
I am doing the following with my program:
1) Write the class definition for a class named Employee with name and salary as employee objects. The class contains two member functions: the constructor and a function that allows a program to assign values to the data members.
2) Add two member functions to the Employee class. One member function should allow any program using an employee object to view the contents of the salary data member. The other member function should allow the program to view the contents of the employee name data member.
3) Add another member function to the Employeeclass. The member function should calculate an employee objects new salary, based on a raise percentage provided by the program using the object. Before calculating the raise, the member function should verify that the raise percentage is greater than or equal to zero. If the raise percentage is less than zero, the member function should display an error message.
4) Write a main function that will create an array of employee objects, assign values to the objects, display the names and current salaries for all objects, ask user for the raise percentage and then calculate and display new salaries for all objects.
However, I receive -2 as my new salary after I input the data from the keyboard. I figured another set of eyes could see what I can't and would highly appreciate if someone can lend a hand, or at least steer me in the right direction. Perhaps it is a logic error, or something wrong with my declarations. Thank you for your time.
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
class EMPLOYEE
{
public:
EMPLOYEE();//
EMPLOYEE(string name, int salary);//
public:
string name;//name to be input
int salary;//salary to be input
int percentage_raise;
int updated_salary;
public:
int enter_values();
int output_values();
int NEW_SALARY();
};
//default constructor
EMPLOYEE::EMPLOYEE()
{
name = "";
salary = 0;
}
//constructor with name/salary variables
EMPLOYEE::EMPLOYEE(string NAME, int SALARY)
{
name= NAME;
salary= SALARY;
}
//name and salary to be input...
int EMPLOYEE::enter_values()
{ cout<<"Enter name and salary: ";
cin>> name;
cin>>salary;
return 0;
}
//output
int EMPLOYEE::output_values()
{ cout<<"Name: "<<name<<endl;
cout<<"Salary: "<<salary<<endl;
return 0;
}
//
int EMPLOYEE::NEW_SALARY()
{
if ( percentage_raise >= 0)
{ int updated_salary;
int raise= (salary *percentage_raise)/100;
updated_salary += raise;
}
else if(percentage_raise< 0)
{ cout<<"Error Message"<<endl;
}
return 0;
}
int main()
{
EMPLOYEE employees[100];
EMPLOYEE percent_to_be_raised;
int i;
for(i =0 ;i<100 ; i++)
{ employees[i]=EMPLOYEE();
employees[i].enter_values();
employees[i].name;
employees[i].salary;
// employees[i].NEW_SALARY();
employees[i].output_values();
cout<<"How much should the salary be raised by?"<<endl;
cin>>percent_to_be_raised.percentage_raise;
cout<<"-----------------------------"<<endl;
cout<<employees[i].name <<"'s new salary is "<<percent_to_be_raised.updated_salary<<endl;
}
}
You need to rewrite this quite alot.
A few pointers:
EMPLOYEE percent_to_be_raised;
Is completely off base. The task states that this calculation should be done in an employee member function. I.e. the raise should be performed as
Employee alfred;
std::cin>> alfred.salary;
double raise;
std::cin>> raise;
alfred.raise_salary(raise); // this is what the task asks for.
Use a naming convention.
Employee
is fine for a c++ class with a capitalized class name convention. EMPLOYEE is not; this looks like a macro name.
Member function usually starts with non-capitalized
Employee::new_salary( the_salary );
Follow the examples you have available from the course material.
Of course
employees[i].name;
employees[i].salary;
Does not do anything. Please review your code in detail and start at the first spot you don't understand.
Note that the OP coding style convention is used to assist the OP. I am aware of the proper naming convention for classes, member functions, and class data members (e.g. see the answer by Captain Giraffe for more).
Inside of:
int EMPLOYEE::NEW_SALARY()
{
if ( percentage_raise >= 0)
{ int updated_salary;
int raise= (salary *percentage_raise)/100;
updated_salary += raise;
}
} // added this to close the function properly
there is a locally declared variable, which is typed identically to the public access data member of the same name. What is the intention here?
Most likely it should be coded like so:
int EMPLOYEE::NEW_SALARY()
{
if ( percentage_raise >= 0)
{
int raise = (salary *percentage_raise)/100;
updated_salary += raise;
}
} // added this to close the function properly
There are design considerations for having all class member data public, as well as having an integer for a percentage. From the calculation above, it looks like only values of one, two, three, etc. are allowed for the percentage number. What is the class supposed to do if a raise is 3.75 percent?
The constructor has to set ALL class data members to something meaningful too. For example, the percentage_raise and updated_salary variables are ignored. Most likely the default constructor has to be updated to:
//default constructor
EMPLOYEE::EMPLOYEE()
{
name = "";
salary = 0;
percentage_raise = 0;
updated_salary = 0;
}
The name and salary constructor has to be updated too. It should probably look like (using the style convention posted by the OP):
//constructor with name/salary variables
EMPLOYEE::EMPLOYEE(string NAME, int SALARY)
{
name = NAME;
salary = SALARY;
percentage_raise = 0;
updated_salary = salary;
}
I doing a freind function program according to this book I have and I did a little of my own code to the program. I puzzle because I get this error message that the "room_num" is undeclared and intellisense identifier "room_num" is undefine. I need help in understanding why this is happen and how to fix it. Here is the code I have been working on for the passed three weeks.
#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;
class HotelRoom
{
friend int Transfer( HotelRoom&, int);
private:
int room_num;
int transroom_num;
int room_cap;
int occup_stat;
double daily_rt;
public:
HotelRoom(int room, int roomcap, int occup, int transroom, double rate = 89.00);
~HotelRoom();
int Display_Number(); //Displays room number and add the method Display_Guest()
int Get_Capacity();
int Get_Status();
double Get_Rate();
int Change_Status(int);
double Change_Rate(double);
void Display_Guest();
};
HotelRoom::~HotelRoom()
{
cout << endl<<endl;
cout << "Guest in room "<<room_num << " has checked out." <<endl;
}
int HotelRoom::Display_Number()
{
return room_num;
}
int HotelRoom::Get_Capacity()
{
return room_cap;
}
int HotelRoom::Get_Status()
{
return occup_stat;
}
int HotelRoom::Change_Status(int occup)
{
occup_stat = occup;
if (occup > room_cap)
{
return -1;
}
else
return occup_stat;
}
double HotelRoom::Get_Rate()
{
return daily_rt;
}
double HotelRoom::Change_Rate(double rate)
{
daily_rt = rate;
return daily_rt;
}
int Transfer(HotelRoom& room_r1, int transroom)
{
//if guest transfers to different hotel room, room is vacant and transroom is now occupied
room_r1.room_num = room_r1.transroom_num;
return room_num;
}
int main()
{
cout<< setprecision(2)
<<setiosflags(ios::fixed)
<<setiosflags(ios::showpoint);
int room = 0;
int roomcap = 4;
int transroom;
int occup;
double rate = 89.00;
cout<<"\nEnter the room number: "<<endl;
cin>>room;
cout<<"\nEnter the amount of guest to occupy this room: "<<endl;
cin>>occup;
cout<<"\nThe guest has decided to transfer rooms"<<endl;
cout<<"\nEnter the room to transfer the guest to"<<endl;
cin>>transroom;
HotelRoom room1(room,roomcap, occup, transroom, rate ); //initialize the object
if (room1.Change_Status(occup) == -1)
{
cout<<"You have exceeded the room capacity"<<endl;
}
else
{
cout <<"\nThe room number is ";
room1.Display_Number();
cout<<"."<<endl;
cout<<"\nThe name of the primary guest is ";
room1.Display_Guest();
cout <<"."<<endl;
cout<<"\nThe number of guest in the room is "<<room1.Change_Status(occup)<<"." <<endl;
cout<<"\nThe daily rate for room "<<room<< " is "<<room1.Get_Rate()<<"."<<endl<<endl;
cout<<"\nYou have tranferred the guest from room"<<room1.Display_Number()<<"to" <<Transfer(room1,transroom)<<endl;
}
cout<<"\nRoom ";
room1.Display_Number();
cout<<" is vacant."<<endl;
system("PAUSE");
return 0;
}
The function Transfer is not a method of HotelRoom, still you are trying to access room_num in it as if it was. You need to specify which room_num of which HotelRoom instance you mean. Probably you meant return room_r1.room_num instead of return room_num.
Also in your Transfer function you never use the parameter transroom, instead you are using a transroom_num from room_r1. This is probably not what you want.
Finally you haven't implemented the constructor and DisplayRoom of HotelRoom. You should create a stubs, which do nothing or print warnings as long as you haven't implemented the methods properly, so you can at least compile and link the code.
Since you are a beginner I would just stick with member functions and class private variables until you get better at it.
As far as the error message, my guess is that inside the function you are using room_num does not have access to the private parts of the HotelRoom class. Notice I said guess, that's because you should copy and paste the text on the output window here so we can see what exactly is happening.
First, you have to identify that room_num is class member variable.
int Transfer(HotelRoom& room_r1, int transroom)
{
room_r1.room_num = room_r1.transroom_num;
//because room_num is not non class member variable, you have to write like below.
return room_r1.room_num;
//return room_num;
}
Secondly, you did not write definition HotelRoom::HotelRoom(int,int,int,int,double), HotelRoom::Display_Guest(void). So you have to write this constructor and function for avoiding error LNK2019.