Yan Shi CS/SE 2630 Lecture Notes 5. Template Yan Shi CS/SE 2630 Lecture Notes
Void Pointer 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! If a void pointer doesn’t know what it’s pointing to, how do we know what to cast it to? Ultimately, that is up to you to keep track of. In general, it is a good idea to avoid using void pointers unless absolutely necessary, as they effectively allow you to avoid type checking. This allows you to inadvertently do things that make no sense, and the compiler won’t complain about it.
Generic 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.
Function Template To declare: 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.
Function Template In some cases the compiler can automatically find out the type. We can also define function templates that accept more than one type of parameter: int i,j; max(i,j); 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);
Class Template 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);
Template Class 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.
Implementing Class Template Two options: put all code for template in .h file //preferred! in the template implementation file (.tpp), precede the member function definition with the template <…> prefix and include this .tpp file at the end of .h file An implementation trick: drive template class from non-template class, put most code in base class template <class ItemType> void Stack<ItemType>::push(ItemType x) { items[height] = x; ++height; } class ComplexContainer { ... }; template<class T> class Container : public ComplexContainer {...};
Non-Type Parameters Can also have non-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 Type checking is guaranteed when using class templates Solution: make DoIt a function template! void DoIt(Stack<char, 10> chs) {…} Stack<char, 20> letters; letters.push(“something”); //illegal! DoIt(letters); //illegal! template<class T, int size> void DoIt(Stack<T, size> stack) {…} Stack<char, 20> letters; DoIt(letters); //OK!
inline Function keyword inline: function is treated as a macro template<class T> inline 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.