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

Wednesday, 2 June 2010

Class initialisation and constructors

There is often lots of confusion with regards to class initialisation. People may forget to take care while using default constructors and copy constructors. Here is a simple example that tries to explain lots of concepts.





//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//This program gives an example of constructors and initialisations

#include<iostream>

using namespace
std;

//Example of a class
class someClass1
{

public
:
//implicit default constructor
int x;
int
*y;
};


//Example of a class with constructor
class someClass2
{

public
:
someClass2(const someClass2& xyz)
{

cout<<"** copy constructor called"<<endl;
x = xyz.x;
y = new int(*xyz.y);
}

//default constructor will have to be explicitly defined
someClass2() {};
//overloading operator '='
const someClass2& operator = (const someClass2& xyz)
{

cout<<"** operator '=' called"<<endl;
x = xyz.x;
y = new int(*xyz.y);
return
*this;
}

int
x;
int
*y;
};


int
main()
{

someClass1 a; //Default initialisation
a.x = 1234;
a.y = new int(6789);

cout<<"someClass1: a.x = "<<a.x<<" a.y( " <<a.y<< " ) = "<<*(a.y)<<endl;

someClass1 b = a; //Copy Initialisation

cout<<"someClass1: b.x = "<<b.x<<" b.y( " <<b.y<< " ) = "<<*(b.y)<<endl;

someClass1 c(a); //Direct Initialisation

cout<<"someClass1: c.x = "<<c.x<<" c.y( " <<c.y<< " ) = "<<*(c.y)<<endl;

//Calling default constructor
someClass2 aa;
aa.x = 2468;
aa.y = new int(3579);

cout<<"someClass2: aa.x = "<<aa.x<<" aa.y( " <<aa.y<< " ) = "<<*(aa.y)<<endl;

//calling copy constructor
someClass2 bb = aa; //Copy Initialisation - note copy constructor will be called

cout<<"someClass2: bb.x = "<<bb.x<<" bb.y( " <<bb.y<< " ) = "<<*(bb.y)<<endl;

//calling copy constructor
someClass2 cc(aa); //Direct Initialisation - note copy constructor called in this case as well

cout<<"someClass2: cc.x = "<<cc.x<<" cc.y( " <<cc.y<< " ) = "<<*(cc.y)<<endl;

someClass2 dd;
//calling operator =
dd = aa;

cout<<"someClass2: dd.x = "<<dd.x<<" dd.y( " <<dd.y<< " ) = "<<*(dd.y)<<endl;

return
0;
}







The output is as follows:

There are certain things worth noting in the above example:
  • In case of someClass1, since only the default constructor is used, the same pointer is used for y in all the cases. This can cause serious problems in the code if one of the classes delete the memory pointed by y for class someClass1. This problem is not present in someClass2
  • If any constructor is defined, it becomes necessary to define the default constructor. You can make sure that nobody uses default constructor in case of someClass2 by making it private (I havent done that because I wanted to show operator =)
  • As you can see in case of variable cc, copy constructor would always be called instead of operator =.
  • operator = would only be called in case of assignment. This is a common mistake.
  • In the code above, cc(aa) is better than using bb = aa even though the results are the same. The main advantage being that it will avoid confusion with operator '=' if its overloaded for a novice and the constructor can be overloaded to take more than one input in future.

Wednesday, 7 April 2010

Example of 'functors'

What are 'functors?'

Depending on what you prefer to read, there are many definitions and explanations of Functors.

From the function pointer tutorial:

Functors are functions with a state. In C++ you can realize them as a class with one or more private members to store the state and with an overloaded operator () to execute the function. Functors can encapsulate C and C++ function pointers employing the concepts templates and polymorphism. You can build up a list of pointers to member functions of arbitrary classes and call them all through the same interface without bothering about their class or the need of a pointer to an instance. All the functions just have got to have the same return-type and calling parameters. Sometimes functors are also known as closures. You can also use functors to implement callbacks.

From StackOverflow:
  • A functor is pretty much just a class which defines the operator(). That makes it "look like" a function.
  • Another advantage to a functor over a pointer to a function is that the call can be inlined in more cases.
  • You can use boost::function, to create functors from functions and methods
Here is a simple example of functors that I have created using mishmash from various places:



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Program to demonstrate the use of functors

#include<iostream>

using namespace
std;

class
someClass
{

public
:
someClass(int x) : someVariable(x) {}
int
operator()(int y) {return (someVariable + y);}
int
internalStateValue(){return someVariable;}

private
:
int
someVariable;
};


int
main()
{

someClass class1(50);
someClass class2(75);

cout<<"Class1 state variable value is : "<<class1.internalStateValue()<<endl;
cout<<"Class2 state variable value is : "<<class2.internalStateValue()<<endl;

int
test1 = class1(22);
cout<<"Test 1 value is : "<< test1<<endl;
int
test2 = class2(22);
cout<<"Test 2 value is : "<< test2<<endl;

cout<<"Class1 final state variable value is : "<<class1.internalStateValue()<<endl;
cout<<"Class2 final state variable value is : "<<class2.internalStateValue()<<endl;

return
0;
}





The output is as follows:

Monday, 1 June 2009

A look at Smart Pointers

There is lot of confucion, misconceptions and misunderstanding regarding smart pointers. After looking at various books and tutorials, i got quite confused till I managed to figure out what they exactly are:

Smart pointers are objects that look and feel like pointers, but are smarter.

To look and feel like pointers, smart pointers need to have the same interface that pointers do: they need to support pointer operations like dereferencing (operator *) and indirection (operator ->). An object that looks and feels like something else is called a proxy object, or just proxy.

To be smarter than regular pointers, smart pointers need to do things that regular pointers don't. What could these things be? Probably the most common bugs in C++ (and C) are related to pointers and memory management: dangling pointers, memory leaks, allocation failures and other joys. Having a smart pointer take care of these things.

The simplest example of a smart pointer is auto_ptr, which is included in the standard C++ library. You can find it in the header , or take a look at Scott Meyers' auto_ptr implementation. Here is part of auto_ptr's implementation, to illustrate what it does:

template <class T> class auto_ptr
{

T* ptr;
public
:
explicit
auto_ptr(T* p = 0) : ptr(p) {}
~
auto_ptr() {delete ptr;}
T& operator*() {return *ptr;}
T* operator->() {return ptr;}
// ...
};

As you can see, auto_ptr is a simple wrapper around a regular pointer. It forwards all meaningful operations to this pointer (dereferencing and indirection). Its smartness in the destructor: the destructor takes care of deleting the pointer.

Lets look at a proper example:

#include<iostream>
#include<memory>


using namespace
std;

class
A
{

public
:
int
*data;
string name;
A(string n): name(n)
{

cout<<"Constructor of A = "<<name.c_str()<<" called "<<endl;
data = new(int);
};

A(string n, int x): name(n)
{

cout<<"Overloaded Constructor of A = "<<name.c_str()<<" called "<<endl;
data = new(int);
*
data = x;
};
~
A()
{

cout<<"Destructor of A = "<<name.c_str()<<" called "<<endl;
delete
(data);
data = this->data;
data = NULL;
}

A* operator ->() { return this;};
};


void
someFunc()
{

auto_ptr<A> a1(new A("a1"));
cout<<"Enter a number and press enter: ";
cin >> (*a1->data);
cout << "a1->data = "<<*a1->data<<endl;

A a2("a2",25);
A *a3 = new A("a3");
}


int
main()
{

cout<<"Before SomeFunc()"<<endl;
someFunc();
cout<<"After SomeFunc()"<<endl;
return
0;
}
The output is as follows:


As you have probably noticed, the instance a3 is never deleted and will cause memory leaks. Using smart pointer would automatically delete the instance a3 and the memory associated with it.

You can read Smart Pointers in much more detail at the References below.

References:
http://ootips.org/yonat/4dev/smart-pointers.html
http://www.geekpedia.com/tutorial47_Smart-Pointers---Part-1.html
http://www.geekpedia.com/tutorial59_Smart-Pointers---Part-II.html

Tuesday, 24 March 2009

Simulating FIFO behaviour with priority queues for equal priorities

In priority queue, the C++ specifications does not define the behaviour of the algorithms when equal-priority items are involved. It is assumed that the ordering is not important in case of a priority queue as long as the same priority items are in correct order as compared to other priorities. For a programmer though this can be important as he expects FIFO ordering for same priority items. To overcome the problem I mentioned in earlier program, we can add another item to get correct FIFO ordering for same priority items.

This is just one approach and there may be other approaches. Also notice that I have used a local variable which requires the order to be input. You can also use the static variable approach for this.


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Example of slightly advanced priority queue making sure that
//along with priorities, queue functionality of FIFO is maintained
#include <iostream>
#include <string>
#include <vector>
#include <queue>

using namespace
std;

class
PrioritizedWord
{

private
:
int
m_prio;
string m_word;
int
m_order; //To set FIFO operation

public
:
explicit
PrioritizedWord()
{ }

explicit
PrioritizedWord(const std::string& word, const int priority = 0, const int order = 0):
m_word(word), m_prio(priority), m_order(order)
{ }

//Operator overloading for priority comparison
const bool operator <(const PrioritizedWord& pW) const
{

if
(m_prio == pW.m_prio)
return
(m_order > pW.m_order);
else
return
(m_prio < pW.m_prio);
}

//Operator overloading to print output
friend ostream& operator <<(ostream& out, const PrioritizedWord& pW)
{

out<<pW.m_word;
return
out;
}

int
getPrio(void)
{
return m_prio;}
string getWord(void)
{
return m_word;}
};


int
main()
{

priority_queue<PrioritizedWord> zahidQueue;

//Note the final order will not be the same as the specs do not
//define behaviour in case two numbers with equal priority exist
zahidQueue.push(PrioritizedWord("First", 23, 1));
zahidQueue.push(PrioritizedWord("Second", 23, 2));
zahidQueue.push(PrioritizedWord("Third", 23, 3));
zahidQueue.push(PrioritizedWord("Fourth", 51, 4));
zahidQueue.push(PrioritizedWord("Fifth", -1, 5));

cout<<"\n\nZahid Queue elements :"<<endl;
while
(!zahidQueue.empty())
{

cout<<zahidQueue.top()<<" "<<endl;
zahidQueue.pop();
}


return
0;
}



The output is as follows:

Monday, 9 March 2009

Simple example of Priority Queue

Here is a simple example of priority queue:



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy

//Example showing how simple priority queues work using C++

#include <iostream>

#include <string>

#include <vector>

#include <queue>



using namespace
std;



class
PrioritizedWord

{


private
:

int
m_prio;

string m_word;



public
:

explicit
PrioritizedWord()

{ }


explicit
PrioritizedWord(const std::string& word, const int priority = 0):

m_word(word), m_prio(priority)

{ }


//Operator overloading for priority comparison

const bool operator <(const PrioritizedWord& pW) const

{


return
(m_prio < pW.m_prio);

}


//Operator overloading to print output

friend ostream& operator <<(ostream& out, const PrioritizedWord& pW)

{


out<<pW.m_word;

return
out;

}


int
getPrio(void)

{
return m_prio;}

string getWord(void)

{
return m_word;}

};




int
main()

{


int
somenum = 2;

while
(somenum > 0)

{


priority_queue<PrioritizedWord> wordQueue, zahidQueue, *temp=NULL;

//Word Queue first time, Zahid Queue second time

if(somenum%2==0)

{


temp = &wordQueue;

}


else


{


temp = &zahidQueue;

}




//Note the final order will not be the same as the specs do not

//define behaviour in case two numbers with equal priority exist

temp->push(PrioritizedWord("First", 23));

temp->push(PrioritizedWord("Second", 23));

temp->push(PrioritizedWord("Third", 23));

temp->push(PrioritizedWord("Fourth", 51));

temp->push(PrioritizedWord("Fifth", -1));



cout<<"\n\nWord Queue elements (All elements lost):"<<endl;

while
(!wordQueue.empty())

{


cout<<wordQueue.top()<<" "<<endl;

wordQueue.pop();

}




cout<<"\n\nZahid Queue elements (Elements preserved):"<<endl;

if
(!zahidQueue.empty())

{


priority_queue<PrioritizedWord> tempQueue;

while
(!zahidQueue.empty())

{


PrioritizedWord &temppW = zahidQueue.top();

cout<<temppW<<" "<<endl;

tempQueue.push(PrioritizedWord(temppW.getWord(), temppW.getPrio()));

zahidQueue.pop();

}


while
(!tempQueue.empty())

{


PrioritizedWord &temppW = tempQueue.top();

zahidQueue.push(PrioritizedWord(temppW.getWord(), temppW.getPrio()));

tempQueue.pop();

}

}




cout<<"\n\nZahid Queue - Removing an element and leaving the rest"<<endl;

{


priority_queue<PrioritizedWord> tempQueue;

while
(!zahidQueue.empty())

{


PrioritizedWord &temppW = zahidQueue.top();



if
(temppW.getWord() != "Second")

{


tempQueue.push(PrioritizedWord(temppW.getWord(), temppW.getPrio()));

zahidQueue.pop();

}


else


{


zahidQueue.pop();

break
;

}

}


while
(!tempQueue.empty())

{


PrioritizedWord &temppW = tempQueue.top();

zahidQueue.push(PrioritizedWord(temppW.getWord(), temppW.getPrio()));

tempQueue.pop();

}

}




cout<<"\n\nZahid Queue elements after removal of element"<<endl;

while
(!zahidQueue.empty())

{


cout<<zahidQueue.top()<<" "<<endl;

zahidQueue.pop();

}


somenum--;

}




return
0;

}


The output is as follows: