Computer Science and Software Engineering
University of Wisconsin - Platteville
Yan Shi
CS/SE 2630 Lecture Notes
void * p;
// Declare like a normal pointer, use the // void keyword as the pointer type.
AKA generic pointer : can be pointed at objects of any data type!
int num; float value = 1.2; p = # p = &value;
— One of its possible uses may be to pass generic parameters to a function.
cannot be dereferenced ! We don’t know the type..
— cast the void pointer before dereference it
— cout << *static_cast<float*>( p );
also cannot do pointer arithmetic ! same reason.
Avoid using void pointers if possible. There are other ways to achieve genetic functions!
What is the purpose of typedef Fruit InfoType;
To make your operation/data structure more generic, we can use a template function/class.
Template: a C++ language construct that allows the compiler to generate multiple versions of a class type or a function by allowing parameterized type.
template<class Type>
Type max(const Type &a, const Type &b)
{ return a > b ? a : b;
}
… max <int> ( 5, 9 ); max <Student> ( mike, alex );
To declare: template < class identifier> function_declaration; template < typename identifier> function_declaration;
To use: function_name <type> (parameters);
Make sure the operations defined in the function template are defined for the type of objects that are using the template.
In some cases the compiler can automatically find out the type.
int i,j; max(i,j);
We can also define function templates that accept more than one type of parameter: template <class T, class U>
T GetMin (T a, U b)
{ return ( a < b ? a : b );
}
… int i,j; long l; i = GetMin<int,long> (j,l);
template<class ItemType> class Stack
{ protected: int height;
ItemType items[50]; public:
Stack() : height(0) { } void push( ItemType x) { items[height] = x; ++height; }
ItemType pop() { height--; return items[height]; } bool isEmpty() const { return height <= 0; } bool isFull() const { return height >= 50; }
};
Stack <Student> stuStack;
Stack <int> nums; nums.push(10);
At compile time, the compiler generates distinct class types and gives its own internal name to each type.
— Stack _Student stuStack;
— Stack _int nums;
The new class types are called template classes.
Similar to template functions.
Two options:
— put all code for template in .h
file //preferred!
— in the implementation file, precede the member function definition with the template <…> prefix template <class ItemType> void Stack<ItemType>::push(ItemType x)
{ items[height] = x;
++height;
}
An implementation trick:
— drive template class from non-template class, put most code in base class class ComplexContainer
{ ... }; template<class T> class Container : public ComplexContainer
{...};
Can also have multiple type parameters: template<class ItemType, int size> class Stack
{ protected: int height;
ItemType items[size]; public:
Stack() : height(0) { } void push(ItemType x) { items[height] = x; ++height; }
ItemType pop() { height--; return items[height]; } bool isEmpty() const { return height <= 0; } bool isFull() const { return height >= size; }
}
…
Stack<int, 100> st;
Type checking is guaranteed when using class templates void DoIt(Stack<char, 10> chs) {…}
Stack<char, 20> letters; letters.push(“something”); //illegal!
DoIt(letters); //illegal!
Solution: make DoIt a function template!
template<class T, int size> void DoIt(Stack<T, size> stack) {…}
Stack<char, 20> letters;
DoIt(letters); //OK!
keyword inline : function is treated as a macro inline template<class T> T sqr(const T &x)
{ return x * x; } the preprocessor converts the code cout << sqr(5); into cout << 5 * 5;
Pros:
— no function call overhead
— compiler optimization
Cons:
— Expand code if inline function is long
— hard to debug: it looks like a function is being called, but it's not really
inline functions should only be in header files!
— compiler must see body of inline function to do the job.
class members defined within class definition are automatically inlined.