• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

Derived classes and function parameters in C++

idNut

Diamond Member
I'm having problems using derived classes and passing their objects. I'll post the .cpp and .h on a site for you to look at.

Header
Code

Just ask me if you have any questions. Passing is really screwing me over because it's saying certain functions don't take the right parameters and this boggles me.
 
I am also new to C++, but here are some of my suggestions to help you out.
In my example I was using VS C++.Net and had to turn off the ?Using the Precompiled headers?.
(Thanks to someone on AnandTech)

Right click on your project in the Solution Explorer.
Click on Properties
Go to the C/C++ item
Go to precompiled headers there.

1) The test driver is in its own .cpp file. In the end you should be able to create:

SavingsAccount my_savings(....<you data here>....);

2) Every class should have it's own .h and .cpp file. An exception to this rule is (for portability sake) when you are designing a template class where you will put the member class back into the .h file.

For your example you should have the following files:
BankAccount.h
BankAccount.cpp
SavingsAccount.h
SavingsAccount.cpp
TestDriver.cpp

3) Use ifndef/define/endif so the definition of the class gets called only once.
#ifndef <some_name_h>
#define<some_name_h>

class some_name
{
public:
protected:
private:
}
#endif //#ifndef <some_name_h>

4) BankAccount should hold all of the common elements to all types of accounts. It has different rules than a SavingsAccount, but still has all of the parts that are common in the base class BankAccount .

5) Your SavingsAccount is derived from the BankAccount. Your line "SavingsAccount : BankAccount" should be "SavingsAccount : public BankAccount"

6) The constructor for SavingsAccount needs all variables for the base class BankAccount since the constructor for the base class is called before the derived class. See my example.

7) Use virtual functions in the base class BankAccount so you can overload functions that are in common in name (See Display and Apply) but may differ in function. What if you add another type of account like a checking account or money market account with different rules? A

8) In BankAccount the variables should be protected not public.

9) Here is what I did for my C++ class?I am using an advance way to initialize the variables in the consrutors. See my note in SavingsAccount.

#ifndef bankaccount_h
#define bankaccount_h
class BankAccount
{
friend std :: ostream& operator << ( std :: ostream& os, const
BankAccount& rhs);
public:
BankAccount(int account_id, const Money& balance);
virtual ~BankAccount(void);

bool operator == (const BankAccount& rhs) const;
bool operator != (const BankAccount& rhs) const;

bool BelongsTo (const Transaction& transaction) const;
virtual void Display( std :: ostream& os ) const;
virtual bool Apply( const Transaction& transaction ) = 0;
protected:
int account_id; // Account id
Money balance; // Current amount of account (money)
};
#endif // #ifndef bankaccount_h

BankAccount :: BankAccount(int accountId, const Money& balanceBA):
account_id(accountId),
balance(balanceBA)
{
};

BankAccount :: ~BankAccount(void)
{
};

#ifndef savingsaccount_h
#define savingsaccount_h
#include ?BankAccount.h?
class SavingsAccount : public BankAccount
{
public:
SavingsAccount(int account_id, const Money& balance, const Date&
last_withdrawl);
~SavingsAccount(void);
virtual bool Apply (const Transaction& transaction);
private:
Date last;
};
#endif // #ifndef savingsaccount_h

SavingsAccount :: SavingsAccount(int accountId, const Money& balanceCA, const Date& last_withdrawl):
BankAccount(accountId, balanceCA),
last(last_withdrawl)
{
// No code
// Instead of last (last_withdrawl) I could of used the following
// within this space.
// last = last_withdrawl
};

SavingsAccount :: ~SavingsAccount(void)
{
};

#ifndef Checking_Account_h
#define Checking_Account_h
class CheckingAccount : public BankAccount
{
public:
CheckingAccount(int account_id, const Money& balance, const Money& overdraft_limit);
~CheckingAccount(void);
virtual bool Apply (const Transaction& transaction);
private:
Money overdraft_limit; //Maximum allowed negative balance
};
#endif //infndefined Checking_Account_h
CheckingAccount :: CheckingAccount(int accountId, const Money& balanceCA, const Money& over_limit):
BankAccount(accountId, balanceCA),
overdraft_limit(over_limit)
{
};

CheckingAccount :: ~CheckingAccount(void)
{
};
 
Thanks for the replies. Spydermag, your code is tough to read but I see what your points are. I just got down reading about some inheritance tips so I'll try to remember them with yours. Do I have to do this whole project over again? I refurnished some of the code for your viewing pleasure. Also, I can't have friend functions period. What's a "Test Driver"? Is that where main() goes?

P6 Code
P6 Header
P6 Header 2

If you could, Spydermag or anyone else who replies with code, put it in a .cpp so I can see indents. It's really tough to try and make all that out. Thanks.
 
Let me guess . . . you started with C didn't you. You don't look like you've picked up object oriented design yet 😉. Just a couple of tips. Instead of having your GetInfo take the parameters for a bank account and a savingsaccount, just creat a GetInfo function in both of them (one will override the other). The bankaccount and savings account data is completely seperate so you can do this (and it doesn't need to even take parameters. have it operate on the local data for each object, and then just call the function for each object just as you pass each one as an arguement right now).

Another thing: in your constructors you're redeclaring your variables. If you have

public:
int iDNumber;

in your header, but then put
int iDNumber = NULL;
in the constructor then it's going to create ANOTHER variable called iDNumber with scope local to the constructor and set it to null (and that value will die when the function call does).

instead use
iDNumber = NULL;
without the declaration. Now granted in this case it doesn't matter since virtually every compiler is going to initialize to NULL anways, but it's a good thing to know (and if you're setting to anything other than 0/NULL it will mess up if you don't do it right).

Also, a purposeful infinite loop is sloppy. You should never do it and should try to avoid using break statements as much as possible (though sometimes you just need to). instead use a do...while() loop. It'll let you execute your prompt once, and then at the end it can determine if the input is valid and if so continue on w/ the program and if not it'll loop again.

More help than this I can't offer right now (I'm sleepy as frell right now). If you haven't figured this out by about noon tommorow (when I'm waking up) then I'll be back on to see if I can help when I've got some sleep.

Good luck on the project (just wait until you get into design patterns 🙂. not only do your teachers make you use inheritance but you're going to have to code a lot of crap in ways that you probably won't like; at least at first).
 

I hope this will clear some things up and help out your design.

The main() function should be your test driver code. I updated yours but left out the the information gathering part.
(I did this on the fly so no guarantees it will work) 🙂

#include <other includes you need>
#include SavingsAcount
int main()
{
SavingsAccount my_accounts[TEN]; // An array of ten savings accounts
int i = 0;
char cProceed = "y";

while ((cProceed=='y'||cProceed=='Y') && (i < 10)
{
cout<<"Do you want to continue? (Y,y/N,n): ";
cin>>cProceed;
if (cProceed=='y'||cProceed=='Y')
{
// Get information to populate BankAccount and SavingsAccount
my_Account.Apply(<varibles for BankAccount and SavingsAccount>;
}
else
{
cout<<"Please enter only y,Y or n,N. "<<endl;
}
i++;
}

for (int j ; j <= i; j++)
{
my_account[j].ShowInfo();
}
return 0;
}

Question: Why do you have both a ISavingsBal and NewSavingsBal? In the end there is only one balance for each account.

Question: Why did you put the balance in SavingsAccount? What if you made a CheckingAccount? A balance could be moved
to BankAccount since it is common to different types of accounts. A derived class should extend the functionality
that is different from the base class.

Question: How about a virtural member function to "Apply" a class "Transaction" to a SavingsAccount. In SavingsAccount
you will also have define a virtural memberfunction "Apply". "Apply" will add to or subtract from the ballance.
"Transaction" will know if this transaction is a deposit or a withdrawl. I added Apply to you classes.

The hierarchy of the derived classed:
BankAccount
SavingsAccount
CheckingAccount
MoneyMarketAccount

To declare a SavingsAccount in you main/Testing program

SavingsAccount my_savings; // Since it is a derived class it has all of the parts of SavingsAccount and BankAcount.

There is another way to do this

BankAccount *BankPtr = new SavingsAccount(); // Same thing but it is a pointer to a BankAccount that also has the
// parts of a SavingsAccount


Classes should be simple and only do what they have to do to benefit the class.

Constructors should do the following:
1) Initialize all class variables
2) Verify data ranges
3) Translate from an outside representation to an internal one. If what was passed in was a integer and the internal is a
pointer to a string then you need to code the conversion routine.
4) Allocate resources?.The internal representation is a dynamically allocated array.

BankAccount::GetInfo() is a bad design. A class should only know how to store and retrive information. You have
made a member function that takes on the job of collecting information to populate itself.

BankAccount::Exit() is also a bad idea since it does nothing for the class BankAcount.

Note: BankAccount: The default constructor needs to initalize all of the variables in BankAccount
BankAccount: Needs another constructor to be able to populate all variables in BankAccount at one time.

File BankAcount.h...Just the class definition
#ifndef BankAccount_h
#define BankAccount_h
class BankAccount
{
public:
char cFname; //First name
char cLname; //Last name
int iIDNumber; //Their ID number

public:
BankAccount();
virtual ~BankAccount(); // Virtual destructor so we clean this up when
// program exits
virtual void Exit();
virtual void ShowInfo(BankAccount Bank[], SavingsAccount Interest[],int);
virtual void GetInfo(BankAccount *Bank, SavingsAccount *Interest);
virtual void CalculateInfo(SavingsAccount *Iinterest);
virtual bool Apply(const Transaction& transaction) = 0;
};
#endif //BankAcount_h

In file BankAccount.cpp all of the member functions that operate on a BankAccount.

BankAccount::BankAccount()
{
char cFName [ARY];
char cLName [ARY];
int iIDNumber = NULL;
}

void BankAccount::CalculateInfo(SavingsAccount *Iinterest)
{
Iinterest->dNewSavingsBal += Iinterest->lSavingsBal * (Iinterest->fInterest/12);
}


void BankAccount::ShowInfo(BankAccount Bank[], SavingsAccount Interest[],int Iindex)
{
for (int iRunMe = NULL;iRunMe<Iindex;iRunMe++)
{
cout<<"Client's first name: "<<Bank[iRunMe].cFname<<endl;
cout<<"Client's last name: "<<Bank[iRunMe].cLname<<endl;
cout<<"Client's identification number: "<<Bank[iRunMe].iIDNumber<<endl;
cout<<"Interest rate: "<<Interest[iRunMe].fInterest<<endl;
cout<<"Current savings balance: "<<Interest[iRunMe].lSavingsBal<<endl;
cout<<"After monthly interest: "<<Interest[iRunMe].dNewSavingsBal<<endl;
}
}


In the file SavingsAccount.h

NOTE: You need to code up the member functions to access these private variables.
SavingsAccount: The default constructor needs to initalize all of the variables in SavingsAccount
SavingsAccount: Needs another constructor to be able to populate all variables in SavingsAccount at once.

#include "BankAccount.h"
#ifndef "SavingsAccount_h"
#define SavingsAccount_h"

class SavingsAccount: public BankAccount //added public to this line
{
private:
float fInterest;
long lSavingsBal;
double dNewSavingsBal;
float fMonthlyInterest;

public:
SavingsAccount();
virtual bool Apply(const Transaction& transaction); // Did this Transaction succeed?

};
#endif //SavingsAccount


In file SavingsAccount.cpp put all the Constructors and member functions to SavingsAccount/
SavingsAccount::SavingsAccount() :
BankAccount() // This calls the default constructor for BankAccount
{
// Initialize SavingsAccount variables
fInterest = 0;
lSavingsBal = 0;
lNewSavingsBal = 0;
fMonthlyInterest = 0;
}
// this is an example
//Second constructor called an Initializing Constructor V V V
SavingsAccount::SavingsAccount( <Put all variables for SavingsAccount and BankAccount here> float f_interest; ) :
BankAccount( <BankAccount variables> ) // This calls the Initializing constructor for BankAccount
{
// Initialize SavingsAccount variables
fInterest = f_interest; // example used here
lSavingsBal = <i_savingsbal>;
lNewSavingsBal = ;
fMonthlyInterest = ;
}
 
Back
Top