Showing posts with label Overloading. Show all posts
Showing posts with label Overloading. Show all posts

Wednesday, 24 November 2010

C++ example of State Design Pattern


The State pattern allows an object to change its behavior when its internal state changes. This pattern can be observed in a vending machine. Vending machines have states based on the inventory, amount of currency deposited, the ability to make change, the item selected, etc. When currency is deposited and a selection is made, a vending machine will either deliver a product and no change, deliver a product and change, deliver no product due to insufficient currency on deposit, or deliver no product due to inventory depletion.

The frequency of use of State Pattern is Medium but is very useful and frequently used Telecoms Protocols implementation.

Example as follows:


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//State is part of Behavioral Patterns
//Behavioral Patterns deal with dynamic interactions among societies of classes and objects
//State allows an object to alter its behavior when its internal state changes.
// The object will appear to change its class

//We will take an example Bank card where depending on the deposit the customers status changes


#include<iostream>
#include<string>
#include "main.h"


Account* State::GetAccount(void)
{

return
account_;
}

void
State::SetAccount(Account* account)
{

account_ = account;
}


double
State::GetBalance(void)
{

return
balance_;
}


void
State::SetBalance(double balance)
{

balance_ = balance;
}


string State::GetStateName(void)
{

return
stateName_;
}


RedState::RedState(State* state)
{

this
->balance_ = state->GetBalance();
this
->account_ = state->GetAccount();
Initialise();
}


void
RedState::Deposit(double amount)
{

balance_ += amount;
StateChangeCheck();
}


void
RedState::Withdraw(double amount)
{

double
newAmount = amount + serviceFee_;
if
(balance_ - newAmount < lowerLimit_)
cout<<"No funds available for withdrawal!"<<endl;
else

balance_ -= newAmount;
}


void
RedState::PayInterest()
{

//No interest is paid
}

void
RedState::StateChangeCheck()
{

if
(balance_ > upperLimit_)
{

account_->SetState(reinterpret_cast<State*>(new SilverState(this)));
delete this
;
return
;
}
}


void
RedState::Initialise()
{

stateName_ = "Red";
//Should come from a data source
interest_ = 0.0;
lowerLimit_ = -100.0;
upperLimit_ = 0.0;
serviceFee_ = 15.0;
}


SilverState::SilverState(State* state)
{

this
->balance_ = state->GetBalance();
this
->account_ = state->GetAccount();
Initialise();
}


SilverState::SilverState(double balance, Account* account)
{

this
->balance_ = balance;
this
->account_ = account;
Initialise();
}


void
SilverState::Deposit(double amount)
{

balance_ += amount;
StateChangeCheck();
}


void
SilverState::Withdraw(double amount)
{

balance_ -= amount;
StateChangeCheck();
}


void
SilverState::PayInterest()
{

balance_ = balance_ * interest_;
StateChangeCheck();
}


void
SilverState::StateChangeCheck()
{

if
(balance_ < lowerLimit_)
{

account_->SetState(reinterpret_cast<State*>(new RedState(this)));
delete this
;
return
;
}

else if
(balance_ > upperLimit_)
{

account_->SetState(reinterpret_cast<State*>(new GoldState(this)));
delete this
;
return
;
}
}


void
SilverState::Initialise()
{

stateName_ = "Silver";
//Should come from a data source
interest_ = 1.0;
lowerLimit_ = 0.0;
upperLimit_ = 1000.0;
}


GoldState::GoldState(State* state)
{

this
->balance_ = state->GetBalance();
this
->account_ = state->GetAccount();
Initialise();
}


void
GoldState::Deposit(double amount)
{

balance_ += amount;
StateChangeCheck();
}


void
GoldState::Withdraw(double amount)
{

balance_ -= amount;
StateChangeCheck();
}


void
GoldState::PayInterest()
{

balance_ = balance_ * interest_;
StateChangeCheck();
}


void
GoldState::StateChangeCheck()
{

if
(balance_ < 0.0)
{

account_->SetState(reinterpret_cast<State*>(new RedState(this)));
delete this
;
return
;
}

else if
(balance_ < lowerLimit_)
{

account_->SetState(reinterpret_cast<State*>(new SilverState(this)));
delete this
;
return
;
}

else if
(balance_ > upperLimit_)
{

cout<<"Your account is too big now. Please consider using Swiss banks"<<endl;
}
}


void
GoldState::Initialise()
{

stateName_ = "Gold";
//Should come from a data source
interest_ = 5.0;
lowerLimit_ = 1000.0;
upperLimit_ = 10000000.0;
}


Account::Account(string owner):owner_(owner)
{

state_ = reinterpret_cast<State*>(new SilverState(0.0, this)); //default
}

Account::~Account()
{

delete
state_;
}


double
Account::GetBalance(void)
{

return
state_->GetBalance();
}


void
Account::Deposit(double amount)
{

state_->Deposit(amount);
cout<<"Deposited $"<<amount<<endl;
cout<<"Balance $"<<GetBalance()<<endl;
cout<<"Status "<<state_->GetStateName()<<endl;
cout<<"\n";
}


void
Account::Withdraw(double amount)
{

state_->Withdraw(amount);
cout<<"Withdrew $"<<amount<<endl;
cout<<"Balance $"<<GetBalance()<<endl;
cout<<"Status "<<state_->GetStateName()<<endl;
cout<<"\n";
}


void
Account::PayInterest()
{

state_->PayInterest();
cout<<"Interest Paid --------"<<endl;
cout<<"Balance $"<<GetBalance()<<endl;
cout<<"Status "<<state_->GetStateName()<<endl;
cout<<"\n";
}


void
Account::SetState(State* state)
{

state_ = state;
}


State* Account::GetState(void)
{

return
state_;
}



//The Main method
int main()
{

Account* account = new Account("Dr. Who");
account->Withdraw(10.00);
account->Withdraw(30.00);
account->Withdraw(70.00);
account->Deposit(234.00);
account->Deposit(5000.00);
account->Withdraw(5200.00);
account->Deposit(1500.00);
account->Deposit(1.00);
account->Withdraw(1200.00);

delete
account;

return
0;
}


EDIT: main.h (added at a later date than the post)





using namespace
std;

//Forward Declaration
class Account;

// The 'State' abstract class
class State
{

public
:
Account* GetAccount(void);
void
SetAccount(Account* account);
double
GetBalance(void);
void
SetBalance(double balance);
string GetStateName(void);
virtual
void Deposit(double amount)=0;
virtual
void Withdraw(double amount)=0;
virtual
void PayInterest(void) = 0;
protected
:
Account* account_;
double
balance_;
double
interest_;
double
lowerLimit_;
double
upperLimit_;
string stateName_;;
};


// A 'ConcreteState' class
// Red indicates that account is overdrawn
class RedState : State
{

public
:
RedState(State* state);
void
Deposit(double amount);
void
Withdraw(double amount);
void
PayInterest();
void
StateChangeCheck();

private
:

RedState(); //Not allowed
void Initialise();
double
serviceFee_;
};


// A 'ConcreteState' class
// Silver indicates less interest bearing state
class SilverState : State
{

public
:
SilverState(State* state);
SilverState(double balance, Account* account);
void
Deposit(double amount);
void
Withdraw(double amount);
void
PayInterest();
void
StateChangeCheck();

private
:
SilverState(); //Not allowed
void Initialise();
};


// A 'ConcreteState' class
// Gold indicates high interest bearing state
class GoldState : State
{

public
:
GoldState(State* state);
void
Deposit(double amount);
void
Withdraw(double amount);
void
PayInterest();
void
StateChangeCheck();

private
:
GoldState(); //Not allowed
void Initialise();
};



// The 'Context' class - defined here as its used for forward declaration
class Account
{

public
:
Account(string owner);
~
Account();
double
GetBalance(void);
void
Deposit(double amount);
void
Withdraw(double amount);
void
PayInterest();
void
SetState(State* state);
State* GetState(void);
private
:
State* state_;
string owner_;
Account();
};




The output is as follows:

Further reading:

http://www.dofactory.com/Patterns/PatternState.aspx




Wednesday, 24 March 2010

Case-Insensitive String comparison

It is often a problem that we ask someone to input some string for comparison but they often put different case and the comparison fails. For example if we are expecting a string, say, 'true'. The user may input 'True' or 'TRUE'. A simple comparison will fail in this case.

The following is a simple program to convert the input string to lower case. What this would allow is to do a case-insensitive search.



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
#include<iostream>
#include<string>

using namespace
std;

//First approach for converting into lower case
string toLowerString(string& input)
{

int
length = input.length();
string output;
for
(int i = 0; i < length; i++)
{

output += tolower(input[i]);
}

return
output;
}


//Second approach for converting into lower case
string toLowerString(string& input, bool approach2) //Overloaded method
{
int
length = input.length();
string output;
for
(int i = 0; i < length; i++)
{

if
(input[i] >= 0x41 && input[i] <= 0x5A) //Ascii for A-Z
output += (input[i] + 0x20); //ascii for a-z
else
output += input[i];
}

return
output;
}


int
main()
{

string s1="true";
string s2("TRUE");
string s3;
s3 = "True";

//Check if s1 = s2
if(s1 == s2)
cout<<"s1 == s2"<<endl;
else

cout<<"s1 != s2"<<endl;

//Check if s1 = s2 with first approach
if(s1 == toLowerString(s2))
cout<<"s1 == Approach1::toLowerString(s2)"<<endl;
else

cout<<"s1 != Approach1::toLowerString(s2)"<<endl;

//Check if s1 = s2 with second approach
if(s1 == toLowerString(s2,true))
cout<<"s1 == Approach2::toLowerString(s2)"<<endl;
else

cout<<"s1 != Approach2::toLowerString(s2)"<<endl;


//Check if s1 = s3 with second approach
if(s1 == s3)
cout<<"s1 == s3"<<endl;
else

cout<<"s1 != s3"<<endl;

if
(s1 == toLowerString(s3,true))
cout<<"s1 == Approach2::toLowerString(s3)"<<endl;
else

cout<<"s1 != Approach2::toLowerString(s3)"<<endl;

//Check if s1 = s3 with second approach
if(s1 == toLowerString(s3))
cout<<"s1 == Approach1::toLowerString(s3)"<<endl;
else

cout<<"s1 != Approach1::toLowerString(s3)"<<endl;

return
0;
}





The output is as follows:


I am aure much better approaches are possible. If you have a better example please share.

Thursday, 30 April 2009

Abuse of try and catch in exception handling

I have seen in some real life code that people sometimes use C++ for their convinience. Rather than solving the problem using powerful C++ features, they take dodgy shortcuts. Here is an example of peice of code that shows this abuse with 2 possible solutions.


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//This example shows how some people abuse throw and catch

#include<iostream>
using namespace std;
//
//The following interface is defined and being used by many classes
void function1();
//Now some programmer wants to change this to
//int function1();
//But this is not possible since overloading does not work for return types
//
//The same problem could instead be solved by other approach as follows:
void function1(int &abc);
int
function1(int dummy1, int dummy2); /*Note 2 dummy to avoid ambiguity with
the first overload. If the above overloaded func was not
there then only 1 dummy is sufficient
*/


int
main()
{

try

{

function1();
}

catch
(int xyz)
{

cout<<"\n\n";
cout<<"The function1() returned "<<xyz<<endl;
cout<<"\n\n";
}


int
first;
function1(first);
cout<<"The 1st overloaded function1() returned "<<first<<endl;
cout<<"\n\n";

cout<<"The 2nd overloaded function1() returned "<<function1(3,4)<<endl;
cout<<"\n\n";

return
0;
}


void
function1()
{

//function logic
throw 100;
}


//Overloaded function1()
void function1(int &abc)
{

abc = 120;
}


//Overloaded function1()
int function1(int dummy1, int dummy2)
{

return
140;
}





The output is as follows:

Sunday, 8 March 2009

More on Vector Manipulation

This is slightly advanced vector manipulation program


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//This program shows advanced vector manipulation
#include<iostream>
#include<vector>

using namespace
std;

//This method prints the vector
void printer(vector<int> v)
{

unsigned int
i;
cout << "Size = " << v.size() << endl;
cout << "Contents = ";
for
(i = 0; i <v.size(); i++)
cout<<v[i]<<" ";
cout<<endl;
}


//Overloaded method same as above but takes pointers
void printer(vector<int*> v)
{

unsigned int
i;
cout << "\nOverloaded Method " << endl;
cout << "Size = " << v.size() << endl;
cout << "Contents = ";
for
(i = 0; i <v.size(); i++)
cout<<*v[i]<<" ";
cout<<endl;
}


int
main()
{

vector<int> v1(5, 1);
cout<<"** Original **"<<endl;
printer(v1);

unsigned int
i;
//Modifying the list above
for(i = 0; i < v1.size(); i++)
v1[i] = i + 3;
cout<<"\n** Modified **"<<endl;
printer(v1);

vector<int>::iterator it;
//Inserting in the list after the first element '0' and after the 4th elem '9 9 9 9'
it = v1.begin();
it += 1;
v1.insert(it,0);
it = v1.begin(); //Crash if you dont do this
it += 5; //Because we inserted '0', 4th element has become 5th.
v1.insert(it, 4, 9);
cout<<"\n** After Insert **"<<endl;
printer(v1);

//Testing Pop back - removes element from the end
v1.pop_back();
v1.pop_back();
cout<<"\n** After couple of Pop back's **"<<endl;
printer(v1);

//New Vector
cout<<endl<<"\n********** NEW *************"<<endl;
vector<int*> v2;
int
*a=new int(5);
int
*b=new int(6);
int
*c=new int(7);
int
*d=new int(11);
v2.push_back(a);
v2.push_back(b);
v2.push_back(c);
printer(v2);
cout<<"\ntwo pop_back and a push_back"<<endl;
v2.pop_back();
v2.pop_back();
v2.push_back(d);
printer(v2);
cout<<"\nClear Vector two"<<endl;
v2.clear();
printer(v2);

return
0;
}




The output is as follows: