330 likes | 442 Views
Week 10. Hand in Lab 6 Templates Lab 7. Templates. Say you’ve written a function like this: int max(int a, int b) { if (a > b) return a; return b; } But now you need another: max(float x, float y). Repetitive code. Max, min, compare Squaring, cubing, combining
E N D
Week 10 • Hand in Lab 6 • Templates • Lab 7 Kate Gregorywith material from Deitel and Deitel
Templates • Say you’ve written a function like this: int max(int a, int b) { if (a > b) return a; return b; } • But now you need another:max(float x, float y) Kate Gregorywith material from Deitel and Deitel
Repetitive code • Max, min, compare • Squaring, cubing, combining • Sorting, normalizing, converting • The type-safety of C++ makes these work well, but can require a lot of code Kate Gregorywith material from Deitel and Deitel
You have choices • Copy and paste • Error prone • Hard to ripple changes through if you change the original • Use #define • Awful because of side effects • Dangerous casts Kate Gregorywith material from Deitel and Deitel
#define macros #define sq(a) a * a int x = sq(2); int y = sq(1+1); • Expands to 1 + 1 * 1 + 1 • 3! Kate Gregorywith material from Deitel and Deitel
#define macros int j=sq(i++); • Expands to i++ * i++ • Answer compiler-dependent • i will be incremented twice • Side effects of macros can be reduced with many extra () but never eliminated • Macros are not a safe road to genericity Kate Gregorywith material from Deitel and Deitel
Dangerous casts void* max(void* a, void* b) • Cast everything you pass to it and everything you get back • Must de-reference pointers • Can’t stop people comparing apples and oranges • Throwing away the entire type system: and for what? The compiler is your friend. Kate Gregorywith material from Deitel and Deitel
Template Functions template<class T> T biggest(T a, T b) { if ( a > b) return a; return b; } • Here T is a placeholder. You can name your placeholders whatever you like Kate Gregorywith material from Deitel and Deitel
Using a template function cout << "biggest of 4 and 5 is " << biggest(4,5) << endl; cout << "biggest of 4.1 and 5.2 is " << biggest(4.1,5.2) << endl; Kate Gregorywith material from Deitel and Deitel
Using a template function Holder h1(4); Holder h2(5); cout << "biggest of h1 and h2 is: " << biggest(h1,h2) << endl; Kate Gregorywith material from Deitel and Deitel
Templates and Operators • The biggest function will only work if Holder has overloaded the > operator • The code using biggest will only work if Holder has overloaded the << operator • Without operator overloading, one template couldn’t work with both fundamental types (eg int) and user defined types (ie classes). • Operator overloading is vital to type-safe genericity Kate Gregorywith material from Deitel and Deitel
What happens here? cout << "biggest of Hello and 2 is " << biggest("Hello", 2); • Compiler error. • Eg: error C2782: 'T biggest(T,T)' : template parameter 'T' is ambiguous Kate Gregorywith material from Deitel and Deitel
What happens here? cout << "biggest of Hello and World is " << biggest("Hello", "World"); cout << "biggest of A and XYZ is " << biggest("A", "XYZ") << endl; cout << "biggest of ABC and Z is " << biggest("ABC", "Z") << endl; • The results are actually compiler specific • Visual C++ 6: second literal string is always “biggest” • Visual C++.NET: first literal string is always “biggest” • It’s based on the numerical value of the pointer Kate Gregorywith material from Deitel and Deitel
More string comparisons char* Hello1 = "Hello"; char* World = "World"; char* Hello2 = "Hello"; cout << "biggest of Hello1 and World is " << biggest(Hello1,World) << endl; • World cout << "biggest of Hello2 and World is " << biggest(Hello2,World) << endl; • Hello Kate Gregorywith material from Deitel and Deitel
Providing a Specific Implementation • What if I wanted biggest to use string length when passed a char* ? template<> char* biggest(char* a, char* b) { if (strlen(a) > strlen(b) ) return a; return b; } Kate Gregorywith material from Deitel and Deitel
Class Templates • Consider writing an Array class like the one presented earlier in this course • self-growing when users attempt to set values past the end of the array • Overloading operator[], operator<< • Preventing access before the beginning of the array • But an Array of What? Kate Gregorywith material from Deitel and Deitel
More Duplication • You could write IntArray, FloatArray, StringArray, and so on • A lot of duplicate work • Or you could write a generic array that worked with void* • What would stop people from mixing object types within an array? • Annoying to cast everything in and out of the array • Couldn’t put literal values (Eg 3) in the array because you can’t take their address Kate Gregorywith material from Deitel and Deitel
Solution template<class C> class Array { private: C* data; int length; public: Array(): data(NULL),length(0) {}; C& operator[](int i); friend ostream& operator<<(ostream& o, const Array& a); }; Kate Gregorywith material from Deitel and Deitel
How do you implement the functions? template<class C> int Array<C>::getlength() { return length; } Kate Gregorywith material from Deitel and Deitel
How do you implement the functions? template<class C> ostream& operator<<(ostream& o, const Array<C>& a) { for (int i=0;i<a.length;i++) { o << a[i] << “ “; } return o; }; Kate Gregorywith material from Deitel and Deitel
How do you use a template? Array<int> ai; ai[0] = 1; ai[3] = 2; cout << ai[2] << endl; cout << ai[5] << endl; Kate Gregorywith material from Deitel and Deitel
Templates work with classes and fundamental types too Array<Holder> ah; ah[0] = h1; ah[2] = h2; cout << ah[0] << endl; cout << ah[1] << endl; cout << ah[4] << endl; Kate Gregorywith material from Deitel and Deitel
Templates impose requirements • In order to work with the Array template, Holder requires: • Default constructor • operator= or single-argument constructor • operator<< • If you try to instantiate a template object and the class is missing some requirements, you’ll receive a compiler error Kate Gregorywith material from Deitel and Deitel
Specialized Overrides • As with function templates, you may need to write a special case for certain types. • For example the Array template needs to initialize extra elements when it grows. It allocates a “scratch” element for this: template<class C> C& Array<C>::operator[](int i) { ... C c; ... • This only works for objects, not for fundamental types or pointers Kate Gregorywith material from Deitel and Deitel
Specialized Overrides template<> int& Array<int>::operator[](int i) { . . . int c=0; . . . } Kate Gregorywith material from Deitel and Deitel
Specialized Overrides template<> char*& Array<char*>::operator[](int i) { . . . char* c = ""; . . . } Kate Gregorywith material from Deitel and Deitel
The Standard Template Library • Arrays, stacks, linked lists and so on are obvious template choices • Why should everyone develop them? • The Standard Template Library offers a variety of “computer science” templates that are likely to be useful in almost every program. • Most modern compilers come with an implementation of the Standard Template Library Kate Gregorywith material from Deitel and Deitel
The vector STL Template #include <vector> . . . vector<int> vi; vi.push_back(1); vi.push_back(2); vi.push_back(3.5); // warning //re truncation vi.push_back(h1); //error: can't //convert Holder to int cout << vi[1] << endl; Kate Gregorywith material from Deitel and Deitel
Going through the whole vector for (int i=0;i<vi.size();i++) cout << vi[i] << " " ; • What if you want them in a specific order? • What if you’re using a collection other than vector? • Not all STL collections provide operator[] access Kate Gregorywith material from Deitel and Deitel
STL Iteration • The STL separates container classes (vector, stack, etc) from objects that know how to go through a container • Iterators can work with a number of different containers • An iterator “points to” each element in turn • Not really, but operator* and operator-> are overloaded Kate Gregorywith material from Deitel and Deitel
Using an Iterator for (vector<int>::iterator it=vi.begin(); it != vi.end(); it++) { cout << *it << " "; } Kate Gregorywith material from Deitel and Deitel
For Next class • Read chapter 14 • Lab 7 • Get ready for the final! • Thursday April 17th, 9am-noon Kate Gregorywith material from Deitel and Deitel