C++ supports the idea of generic programming using templates. In essence, templates allow you to define classes or functions that operate on an arbitrary type of data, instead of a specific type.
T (but you could
call it anything):
template< typename T >
void swap( T& first, T& second ) {
T temp = first;
first = second;
second = temp;
}
...
int i = 42, j = -1;
swap( i, j );
char c = 'a', d = 'x';
swap( c, d );
string s1 = "A man, a plan, a canal...";
string s2 = "...panama!";
swap( s1, s2 );
This templated function swaps the first and second arguments.
Since the arguments are passed as references, the swap will "stick"
after the function finishes. Note that this templated function can be
passed arguments of primitive types (like int or
char) or arguments that are classes (like
string).
Templates can also be used with classes. Remember our Array class from before, which held an array of integers? With templates, our Array class can hold almost any data type:
// an array that will hold a generic type T
template< typename T >
class Array {
friend ostream& operator<<( ostream& os, const Array& arr ) {
os << "[ ";
for( int i = 0; i < arr.length; i++ ) os << arr.data[i] << " ";
os << "]";
return os;
}
public:
Array( int i = 10 ) {
data = new T[i]; // use T just like a regular type
length = i;
}
Array( const Array& arr ) {
data = new T[arr.length]; // again, T is our type
length = arr.length;
}
~Array() {
delete[] data;
}
Array& operator=( const Array& arr ) {
if( this != &arr ) {
if( length != arr.length ) {
delete[] data;
data = new T[arr.length];
length = arr.length;
}
for( int i = 0; i < arr.length; i++ ) data[i] = arr.data[i];
}
return *this;
}
T& operator[]( int idx ) { // our array-access operator will
return data[idx]; // return a reference to a T
}
private:
T* data; // this will hold our array of type T
int length;
};
...
// make an array of characters
Array<char> arr1(26);
for( int i = 0; i < 26; i++ ) arr1[i] = i+'a';
cout << arr1 << endl;
// make an array of integers
Array<int> arr2(10);
for( int i = 0; i < 10; i++ ) arr2[i] = i*i;
cout << arr2 << endl;
Just like with our templated swap function, the class definition is
preceded by the template keyword along with our generic
type name (which we again call T). We can then create an
instance of our templated class by typing (for example)
Array<string> stringArray(10);
The STL is a collection of data structures and algorithms that use
templates to operate on generic types. For example, the STL defines a
vector class that can hold an arbitrary amount of any
data type for you -- like our Array class above, but much, much,
better! Here is list of some of the data structures that the STL
provides for you:
You can use the STL just like you'd use the Array class we defined above:
#include <vector>
using std::vector;
...
vector<int> v;
for( int i = 0; i < 10; i++ ) v.push_back(i); // add 0-9 to our vector
...
for( int i = 0; i < v.size(); i++ ) { // use v.size() to get the size
cout << v[i] << endl; // overloaded array-access operator!
}
The STL also provides a variety of useful algorithms that can
operate on STL containers like vectors. Many of the STL algorithms
use iterators
to read and write from containers. You can think of iterators as
pointers to elements in a container. For most containers (like
vectors) you can get an iterator to the first element with the
begin() function and an iterator to the last element with
the end() function.
#include <vector>
using std::vector;
#include <algorithm>
...
vector<string> v;
string i;
while( cin >> i ) v.push_back(i); // read strings from input, put them in a vector
random_shuffle( v.begin(), v.end() ); // shuffle the strings randomly. Use the begin() and
// end() functions to get iterators to the beginning
// and end of the vector, which denotes the range that
// we want to shuffle.
cout << "v: [ ";
for( int i = 0; i < v.size(); i++ ) cout << v.at(i) << " ";
cout << "]" << endl;
// display the smallest element. We have to dereference the iterator that
// min_element returns to get the actual value that the iterator points to.
cout << "Max: " << *min_element(v.begin(), v.end()) << endl;
// sort the vector!
sort( v.begin(), v.end() );
cout << "v: [ ";
for( int i = 0; i < v.size(); i++ ) cout << v.at(i) << " ";
cout << "]" << endl;
// look for a certain string: the word "secret"
vector<string>::iterator result = find( v.begin(), v.end(), "secret" );
if( result != v.end() ) cout << "You entered the secret word!" << endl;