Author : Vijay Mukhi
Page : << Previous 2
Such a move, we believe will be sufficient to silence our detractors.
Program 4 :
#include <stdio.h>
template <class T> class zzz
{
public:
T print( T i)
{
return i;
}
};
main()
{
zzz <int> k;
printf("%d\n",k.print(100));
}
In the above program when we chose to have int as a parameter to 'zzz' nothing stops us from saying printf("%d\n",k.print(100)); In this case T becomes int, so the return value will also be an int. For those who are all at sea, we will first attempt to understand the mechanics involved. This should be enable us to obtain a cleared picture of the whole affair. Writing code become increasingly complicated because at the time of writing the code, we are not aware of the datatype of 'i', assuming it's datatype is fraught with dangers as we can assume that 'i' could be anything. This makes the whole program dynamic. Return values can also be dynamic in nature. Programs involving pointer can assume dynamic nature because of a simple reason. As 'char' and not 'char *' is a datatype similarly 'T' is a datatype which is available at compile time, hence T *i becomes a pointer to 'T' which can point to any datatype. Before we bit adieu to the Template Classes, we provide the last example of the series.
Program 5 :
#include <stdio.h>
template <class T,int j> class zzz
{
public:
zzz()
{
char a[j];
printf("j=%d\n",j);
a[0]='s';
}
};
main()
{
zzz <int,6> a;
}
When we say 'zzz <int,6> a', 6 becomes the value of j. Since we have said class T, the class signifies that we are deciding the data type of T, instead if we had chosen to use a variable, then we are saying that when C++ create something called zzz, we are going to give that variable a value. This could not be done in C++ if had not used templates. So the whole idea of templates is that you can decide the data types of variables when we want to plus we can introduce variables which will have certain values. So the whole idea is that we can write code which is abstract and more generic.
The overloaded programmer and function :
People have very volatile memories. They would have probably forgotten all about operator overloading and the related concepts. So to refresh their memories we have presented a small example which will act as a revision for them.
Program 6 :
#include <stdio.h>
class zzz
{
public :
int i,j;
zzz(int x = 0, int y=0)
{
i=x;j=y;
}
void print()
{
printf("%d..%d\n",i,j);
}
void operator = (zzz d)
{
printf("%d..%d..%d..%d\n",i,j,d.i,d.j);
i=d.i;
j=d.j;
}
};
main()
{
zzz a(1,2);
zzz b(10,11);
a=b;
a.print();
}
In the above program all that we have to understand is that if we write 'a=b', for some reason we don't get an error, a will now have it's i and j equal to that of b. This is no black magic. It so happens that when we wrote 'a=b', we actually wrote a.=(b); It simply means that the operator should be understood as a function, so when we say operator = it is a function which takes a 'zzz' and the return value is a void. Please take into account the fact that when we write i and j, we are not writing i and j, but we are writing 'this->i' and 'this->j'. So now here if we choose to display the values, the 'd.i' and the 'd.j' will be that of b which is 10 and 11, whereas 'i' and 'j' will be that of a. If we say that i = d.i and j=d.j this will work right in the above program but not in the next program.
Program 7 :
#include <stdio.h>
class zzz
{
public :
int i,j;
zzz(int x = 0, int y=0)
{
i=x;j=y;
}
void print()
{
printf("%d..%d\n",i,j);
}
zzz operator = (zzz d)
{
printf("%d..%d..%d..%d\n",i,j,d.i,d.j);
i=d.i;
j=d.j;
//return *this;
return d;
}
};
main()
{
zzz a(1,2);
zzz b(10,11)
zzz c(100,101);
c=a=b;
a.print();
c.print();
}
The multiple occurrences of '=' will not work So we have no choice but to say that the return value is zzz and then we can return either d or alternately we can say *this, where 'this' is a pointer.
Since we can be in an extremely kinky mood and would like to say here
a->i and a->j The question is can we pull it off? We can say 'this' because a happens to be an object, not a pointer. Had it been a pointer then we would have had no problems at all. For the ones with the volatile memory, let us remind them that the = is an operator so let's stop here and have a good look at the outcome.
Program 8 :
#include <stdio.h>
class zzz
{
public :
int i,j;
zzz(int x = 0, int y=0)
{
i=x;j=y;
}
void print()
{
printf("%d..%d\n",i,j);
}
void operator -> ()
{
printf("%d..%d\n",i,j);
}
};
main()
{
zzz a(1,2);
a->i=1000;
}
When we are saying a->, we are overloading the ->. When we say that we are overloading the ->, a-> has to stand for something. For the kinkier minds let's present a question. Can a-> stand for void? The answer is a obvious no - We get an error.
Program 9 :
#include <stdio.h>
class zzz
{
public :
int i,j;
zzz(int x = 0, int y=0)
{
i=x;j=y;
}
void print()
{
printf("%d..%d\n",i,j);
}
zzz * operator -> ()
{
printf("%d..%d\n",i,j);
return this;
}
};
main()
{
zzz a(1,2);
a->i=1000;
a.print();
}
When we say a->, all that we are saying is that -> is an operator. But it is an unary operator. So we have actually written this as 'a.->', no parameter needed. Because it is a unary operator like the ++. Unary operator do not take any parameters . So because it is an unary operator, the -> function gets called and we are saying that it returns 'this'. What is this, it a pointer to 'zzz'. So this like saying a.i = 1000. We just wanted to show you that the -> is an operator . It can be overloaded. If you are questioning your wisdom of painstakingly going through the entire tutorial without a mention of VC++ 5.0, you are probably wondering as to where you can use all this knowledge. We will answer that question after you have checked out our next program.
Program 10 :
#include <stdio.h>
class aaa
{
public:
int i;
void print()
{
printf("%d..aaa\n",i);
}
};
class bbb
{
public:
int j;
void print()
{
printf("%d..bbb\n",j);
}
};
class ccc
{
public:
int k;
void print()
{
printf("%d..ccc\n",k);
}
};
template <class T>
class zzz
{
public :
T p;
T * operator ->()
{
return &p;
}
};
main()
{
zzz <bbb> a;
a->j=100;
a.p.print();
zzz <aaa> b;
b->i=10;
b.p.print();
}
The three classes (aaa, bbb, ccc) are useless classes. The real work gets done in class 'zzz'. If we have to create an object that looks like zzz, we will have to say zzz<****> a; Depending upon what we write within the angle brackets, the value of b changes. we are allowed to say a.p.print. So if we change aaa to bbb or ccc, print gets called. If we say a->j. it will spew out an error message for aaa and ccc. When we say operator -> and return &T it implies that aaa, bbb, ccc are collection of functions, variables. An OCX is a similar concept, it is nothing but a collection of properties, methods, events. Properties, methods, events are nothing but variables and functions. So if we now create an object 'a' that looks like zzz and we give it bbb as the parameter, then we have the capability of referencing all the members of bbb. If instead we choose to replace 'bbb' with 'ccc' then we can access all the members of 'ccc'.
This lays before us an unprecedented amount of flexibility. The three classes mentioned above can have their unique identification code, which may be tentatively be called as it's UUID. We could also have some code in zzz like 'CreateInstance' which will have the ability to call (invoke) any class that we might choose to use. That means from 'a' we can call all the functions that we desire. So if there are twenty functions then we can call any or all these twenty. That is the first advantage. But the second advantage is that that our code remains the same. Which implies that we will always say zzz a , and by using a->, we can access all functions that we ever dreamt of. That is what we mean by smart pointers.
Page : << Previous 2