I have an inheritance heirarchy and I need to use polymorphism.

I have some questions because i don't really understand it fully.

What i have to do is create a vector of pointers (account) to 2 of my derived class objects, SavingsAccount and CheckingAccount.

Then for each account in my vector I need to determine its type so i can use member functions to perform actions

I don't know if i need to and which functions in my classes i need to make virtual and how i create the vector of account pointers.

I have included my classes that I have for my heirarchy and the code for my test program which i know won't work yet.

I just need to fill the gaps which creates the vector with the pointers and to find out how to add to the vector for the number of accounts.

here is my test program

//#include "SavingsAccount.hpp"
//#include "CheckingAccount.hpp"
#include <iomanip>
#include <vector>
#include <iostream>

using namespace std; 

int main() {
	
	//vector<Account> accounts;
	
	//Account *sAccount = new SavingsAccount;
	//Account *cAccount = new CheckingAccount;
	
	double getWithdrawal;
	double getDeposit;
	int num_accounts;
	
	cout << "Number of accounts to be processed: ";
	cin >> num_accounts;
	
	//accounts.resize(num_accounts);
	
	for(int i=0; i < num_accounts; i++) {
	
		cout << "Account " << i+1 << " balance: " << endl;
		
		cout << "Enter an amount to withdraw from Account " << i+1 << ": ";
		
		cin >> getWithdrawal;
		
		cout << "Enter an amount to deposit into Account " << i+1 << ": ";
		
		cin >> getDeposit;
	}
	
	return 0;
}

I think i can do the bits between the for loop which performs the actions but i just need to determine the account type

Recommended Answers

All 14 Replies

Member Avatar for jencas
vector<Account> accounts;

You need a pointer or a reference for polymorphism, so this won't work.
Do you really need to differentiate between the two types of account or is it sufficient to implement different behaviour in virtual methods? If you really need it use RTTI, if you can't use even this, use an enum or whatever and let a GetType() Method return the class specific value.

I forgot to attach my files (they're all really hpp files).....

I've now changed any functions in the classes to virtual after reading my C++ book (very simple code extracts and explanations)

How do I create a vector of (Account) pointers and loop through each of them processing each account?

Also how do i use getType() to determine the account type?
I have a theory of using a switch or if statement using the getType() and have different branches depending on the account type.

#include "PolySavingsAccount.hpp"
#include "PolyCheckingAccount.hpp"
#include <iomanip>
#include <vector>
#include <iostream>

using namespace std; 

int main() {
	
	//vector<Account> accounts(4);
	
	//declare pointers
	Account *account1 = new SavingsAccount;
	Account *account2 = new CheckingAccount;
	Account *account3 = new SavingsAccount;
	Account *account4 = new CheckingAccount;
	
	//variables for withdrawl and deposit amounts
	double getWithdrawal;
	double getDeposit;
	
	//loop through each of the accounts processing each one
	for(int i=0; i < 4; i++) {
		//display the account's current balance 
		cout << "Account " << i+1 << " balance: " << accounti+1 -> getBalance() << endl;
		
		//request a withdrawal amount from the account
		cout << "Enter an amount to withdraw from Account " << i+1 << ": ";
		cin >> getWithdrawal;
		//call this accounts debit function
		accounti+1 -> debit(getWithdrawal);
			
		//request a deposit amount for the account
		cout << "Enter an amount to deposit into Account " << i+1 << ": ";	
		cin >> getDeposit;
		//call this account's credit function
		accounti+1 -> credit(getDeposit);
		
		//display the account's new balance
		cout << "Account " << i+1 << " balance: " << accounti+1 -> Account::getBalance() << endl;
	}
	
	return 0;
}

i tried running the above code but i get these errors (no surprise)

PolyTestAccount.cpp
PolyTestAccount.cpp(14) : error C2512: 'SavingsAccount' : no appropriate default
constructor available
PolyTestAccount.cpp(15) : error C2512: 'CheckingAccount' : no appropriate defaul
t constructor available
PolyTestAccount.cpp(16) : error C2512: 'SavingsAccount' : no appropriate default
constructor available
PolyTestAccount.cpp(17) : error C2512: 'CheckingAccount' : no appropriate defaul
t constructor available
PolyTestAccount.cpp(26) : error C2065: 'accounti' : undeclared identifier
PolyTestAccount.cpp(26) : error C2227: left of '->getBalance' must point to clas
s/struct/union/generic type
type is 'int'
PolyTestAccount.cpp(32) : error C2065: 'accounti' : undeclared identifier
PolyTestAccount.cpp(32) : error C2227: left of '->debit' must point to class/str
uct/union/generic type
type is 'int'
PolyTestAccount.cpp(38) : error C2065: 'accounti' : undeclared identifier
PolyTestAccount.cpp(38) : error C2227: left of '->credit' must point to class/st
ruct/union/generic type
type is 'int'
PolyTestAccount.cpp(41) : error C2065: 'accounti' : undeclared identifier
PolyTestAccount.cpp(41) : error C2227: left of '->getBalance' must point to clas
s/struct/union/generic type
PolyTestAccount.cpp(41) : error C2232: '->Account::getBalance' : left operand ha
s 'int' type, use '.'

Member Avatar for jencas
Account *account1 = new SavingsAccount;
	Account *account2 = new CheckingAccount;
	Account *account3 = new SavingsAccount;
	Account *account4 = new CheckingAccount;

Here you need to provide the parameters for each account!

accounti+1

You cannot "calculate" variable names in C++.

Member Avatar for jencas

Perhaps you should define default parameter for your constructors, i.e.

//constructor
explicit SavingsAccount(double initBalance = 0.0, double  initInterestRate = 5.0)
	: Account(initBalance),  InterestRate(initInterestRate)
	{}

I added some paramaters
//declare pointers

Account *account1 = new SavingsAccount(25.00, 1.00);
Account *account2 = new CheckingAccount(80.00, 1.00);
Account *account3 = new SavingsAccount(200.00, 1.00);
Account *account4 = new CheckingAccount(400.00, 1.00);

so that error seems to have cleared up but how do i increment the account so it changes to account1, accout2 etc on each cycle of the loop?

I was able to get the vector to work and support the polymorphism:

vector<Account *> accounts;

	accounts.push_back(new SavingsAccount(25.00, 1.00));
	accounts.push_back(new CheckingAccount(80.00, 1.00));
	accounts.push_back(new SavingsAccount(200.00, 1.00));
	accounts.push_back(new CheckingAccount(400.00, 1.00));

	for each (Account * pacct in accounts)
	{
		cout << "Original Balance: " << pacct->getBalance() << endl;
		pacct->credit(5);
		cout << "New Balance: " << pacct->getBalance() << endl;
	}

The checking accounts get the fee applied to the credit.

Murtan to the resuce again....i would buy you a beer if i could so i'll have to give you loads of rep points.

I have it working spot on now but just another question.....

How do i go about calling a function like this if the account type is only a savings acccount?

pacct->credit(pacct->CalculateInterest());

I would presume to use an if statement of some sort but i don't know what the condtion would be. Also is that correct what i did in that code snippet?

I only want to call that function if the account type is savings.

If you have to use RTTI as part of the assignment, then google it. Otherwise do as the others sugguested. Implement in the base class (the one you derived the 2 accounts from?) a virtual method that returns a bool. Now provide an override in the 2 inherited classes, one returning true, the other false. (I say bool because there's only 2, otherwise you should use enumeration/code). And voila, you built yourself a type checker which can be called polymorhpically.

I've looked at type casting and have come up with this and it does compile but when i run the program and i check to see what account it is, it doesn't recognise a SavingsAccount object so the if statement is not taken.

if (typeid(Account *)==typeid(SavingsAccount)) {
        cout << "Interest earned" << endl;
}

I've looked at type casting and have come up with this and it does compile but when i run the program and i check to see what account it is, it doesn't recognise a SavingsAccount object so the if statement is not taken.

if (typeid(Account *)==typeid(SavingsAccount)) {
        cout << "Interest earned" << endl;
}

Unless its an RTTI assignment, you probably shouldn't use it. Use the method I described earlier.

In your code, an "Account *" will never be a "SavingsAccount" you are directly comparing two types. You wanted to compare an instance and a type. The following worked for me:

if (typeid(*pacct) == typeid(SavingsAccount)) {
    cout << "  Savings Account" << endl;
} else if (typeid(*pacct) == typeid(CheckingAccount)) {
    cout << "  Checking Account" << endl;
} else {
    cout << "  Unrecognized: " << typeid(*pacct).name() << endl;
}

An alternative implementation might be to add a virtual 'month end' method that would add interest to a savings account and charge a service charge to a checking account (unless they met the minimum balance requirements :) )

That makes perfect sense and it seems so obvious now.

How can i call functions within the savings class withing the if statement so if the account type is savings i can call a function in that class?

If i try pacct->CalculateInterest() it doesn't reggnise it because it's not a function of the account class (which i knew) so i am presuming there must something between pacct-> and ->CalculateInterest()

Once you 'know' what class it actually is, you can cast the pointer...

if (typeid(*pacct) == typeid(SavingsAccount)) {
    SavingsAccount * pSave = (SavingsAccount *)pacct;
    // or more explicitly
    SavingsAccount * pSave = reinterpret_cast<SavingsAccount *>(pacct);
    // then
    pSave->credit(pSave->CalculateInterest());
}

But a better implementation really would be to define all of the functionality that you might ever expect from an account in the base class with virtual methods so you don't have to jump through the 'what type is it' and 'make it one of what it is' hoops.

You could either implement something like virtual int ProcessMonthEnd() which in the base Account class might do nothing. Then in the derived classes it is overridden to do what that account type needed (for example posting interest to a SavingsAccount).

for each (Account * pacct in accounts)
{
    pacct->ProcessMonthEnd();
}

Or you might decide that any account might earn interest. So you implement virtual bool EarnsInterest(); and virtual double CalculateInterest(); in Account. The base Account implementation would return false and 0, but the methods could be overridden (say in SavingsAccount) to return true and the current interest calculation.

for each (Account * pacct in accounts)
{
    if (pacct->EarnsInterest()) {
        pacct->credit(pacct->CalculateInterest());
    }
}

As long as the methods are declared as part of Account, you can call them without having to cast anything.

(My personal preference would be to avoid the RTTI and casting, but it is YOUR code.)

We are definitely headed into the 'implementation specific' details. The choice of which of the above (if any) works for you is based on how you see the classes and how you expect them to be used. I'm not sure there's a "right way" to do it, just alternatives that have pro's and con's depending on what your goals are.

This is where the class designer (in this case, you) earns his pay. The goal is to come up with an implementation that makes sense and that hopefully isn't too hard to use.

Many thanks Murtan......work exactly how it should

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.