Presentation is loading. Please wait.

Presentation is loading. Please wait.

C++ Templates L03 - Iterator 10 – Iterator.

Similar presentations


Presentation on theme: "C++ Templates L03 - Iterator 10 – Iterator."— Presentation transcript:

1 C++ Templates L03 - Iterator 10 – Iterator

2 Attendance Quiz #12 Program Correctness

3 Tip #10: Standard Integer typedefs
Iterators The actual size of integer types varies by implementation. The standard only requires size relations between the data types (i.e., a long long is not smaller than long, which is not smaller than int, which is not smaller than short.) As char's size is always the minimum supported data type, no other data types (except bit-fields) can be smaller. The following pre-processor macros are defined in the header file <stdint.h>: signed unsigned Description int8_t uint8_t Integer type with a width of exactly 8, 16, 32, or 64 bits. For signed types, negative values are represented using 2's complement. No padding bits. int16_t uint16_t int32_t uint32_t int64_t uint64_t std::size_t Largest unsigned integer type; the size of any object in bytes; widely used in the standard library to represent sizes, lengths, and counts.

4 Strings Are Really Templates
C++ Templates Strings Are Really Templates

5 Template Classes and Functions
Iterators C++ templates use "Instantiation-style polymorphism". A template is literally a template; a class template is not a class, it's a recipe for creating a class using template parameters. Class and function functionality can be adapted to more than one type or class without repeating the entire code for each type. template <typename T> class MyPair { private: T values [2]; public: MyPair (T first, T second) values[0]=first; values[1]=second; } }; MyPair<int> myInts(115, 36); MyPair<double> myFloats(3.0, 2.18); template <typename int> int GetMax(int a, int b) { return (a > b ? a : b); } int x,y; GetMax<int>(x, y); template <typename myType> myType GetMax(myType a, myType b) { return (a > b ? a : b); } T is the template parameter name instead of myType because it is shorter and in fact is a very common template parameter name. But you can use any identifier you like.

6 Lab 03 - Iterator

7 Array Container Access
Iterators By Index #include <iostream> using namespace std; int main() { int dog[] = { 1, 2, 3, 4 }; int* dptr = dog; for (size_t i = 0; i < 4; ++i) cout << *dptr++ << endl; } return 0; By Pointer #include <iostream> using namespace std; int main() { int dog[] = { 1, 2, 3, 4 }; for (size_t i = 0; i < 4; ++i) cout << dog[i] << endl; } return 0;

8  Other Containers #include <iostream> #include <vector>
Iterators #include <iostream> #include <vector> using namespace std; int main() { vector<int> myArray; myArray.push_back(1); myArray.push_back(2); myArray.push_back(3); myArray.push_back(4); for (size_t i = 0; i < myArray.size(); ++i) cout << myArray[i] << endl; } return 0; #include <iostream> #include <list> using namespace std; int main() { list<int> myArray; myArray.push_back(1); myArray.push_back(2); myArray.push_back(3); myArray.push_back(4); for (size_t i = 0; i < myArray.size(); ++i) cout << myArray[i] << endl; } return 0;

9 Why Use an Iterator? When avoiding iterators:
Assumes your container has index ([]), at, and increment (++,--)operators. Assumes container elements can be randomly accessed, are contiguous, and same size (true for vector but not for many other containers.) Requires many versions of common algorithms (ie., sort, reverse, etc.) Iterators bring you closer to container independence. You're not making assumptions about random-access ability, storage format, or efficiency of operations such as size(). You only need to know that the container has iterator capabilities. Iterators enhance your code further with standard algorithms. Depending on what it is you're trying to achieve, you may elect to use std::for_each(), std::transform(), std::sort() and so on. By using a standard algorithm rather than an explicit loop you're avoiding re-inventing the wheel. Your code is likely to be more efficient (given the right algorithm is chosen), correct and reusable.

10 The STL Iterator Approach
Iterators #include <iostream> #include <list> using namespace std; int main() { list<int> myArray; myArray.push_back(1); myArray.push_back(2); myArray.push_back(3); myArray.push_back(4); list<int>::iterator iter = myArray.begin(); while (iter != myArray.end()) cout << *iter << " "; ++iter; } return 0; #include <iostream> #include <vector> using namespace std; int main() { vector<int> myArray; myArray.push_back(1); myArray.push_back(2); myArray.push_back(3); myArray.push_back(4); vector<int>::iterator iter = myArray.begin(); while (iter != myArray.end()) cout << *iter << " "; ++iter; } return 0; iter "points" to first element in myArray. myArray.end() "points" after the last element in myArray. Dereference iter to access myArray element.

11 Iterator Lab Iterators The concept of an iterator is fundamental to understanding the C++ Standard Template Library (STL). Iterators provide access to data stored in container classes (e.g. vector, map, list, etc.) Your Iterator lab implements a C++ array container class that uses an iterator to access the array elements. Your container supplies begin() and end() functions. Your iterator object overloads the not equal ("!="), dereference ("*"), and pre-increment ("++") operators. Use an iterator to sequentially access elements of the associated array class. Read integer values from a file into the array class. Instantiate an iterator using the begin() function and then use the iterator to iterate thru the array values until the iterator equals the iterator returned by the end() function.

12 Nested Class MyArray Iterator Iterators template<typename T>
{ private: // MyArray data public: MyArray(const size_t maxSize) { ... } void push_back(T item) { ... } std::string toString() const { ... } friend std::ostream& operator<< (std::ostream& os, const MyArray<T>& myArray) {…}; }; MyArray Iterator class Iterator { private: // Iterator data and private functions public: Iterator(T* array, size_t size, size_t index) { ... } bool operator!= (const Iterator& other) const { ... } // not-equal Iterator& operator++ () { ... } // pre-increment ++ T& operator*() const { ... } // dereference std::string toString() const { ... } friend std::ostream& operator<< (std::ostream& os, const Iterator& iter) {…} }; Iterator begin() { ... } // pointer to first element Iterator end() { ... } // pointer AFTER last element

13 main Open I/O Streams Read / push_back integer into numbers container.
Iterators int main(int argc, char * argv[]) { VS_MEM_CHECK; MyArray<int> numbers(MAX_ARRAY_SIZE); ifstream in(argv[1]); std::ostream& out = (argc < 3) ? std::cout : *(new std::ofstream(argv[2]); out << endl << endl; int i; while (in >> i) numbers.push_back(i); out << numbers << endl << endl; out << "SEQUENTIAL" << endl; MyArray<int>::Iterator iter = numbers.begin(); out << "iter: " << iter << endl; for (; iter != numbers.end(); ++iter) out << *iter << " "; return 0; } Open I/O Streams Read / push_back integer into numbers container. Instantiate Iterator Use friend insertion operator to examine Iterator Output number's contents using dereferencing operator Loop until iter and numbers.end() are equal

14 Output of Iterator Lab myArray: 1 2 3 4 5 6 7 8 9 10
Iterators myArray: ITERATORS: begin(): size=20 index=0 end(): size=20 index=20 SEQUENTIAL: PRIME: COMPOSITE: 18 20 FIBONACCI: 3 = 1 + 2

15 You may freely use the code in any way you deem useful.
****Disclaimer**** The following code examples are flawed and incomplete, but demonstrate how an iterator class might be implemented. You may freely use the code in any way you deem useful.

16 Step 1 – int Array Class Iterators #include <iostream> #include <string> #include <sstream> #define MAX_ARRAY_SIZE using namespace std; class MyArray { private: size_t size_; int* array_; public: MyArray(size_t maxSize) : size_(0) { array_ = (int*)malloc(maxSize * sizeof(int)); } void push_back(int item) { array_[size_++] = item; } }; int main(int argc, char * argv[]) { MyArray numbers(MAX_ARRAY_SIZE); numbers.push_back(1); numbers.push_back(2); numbers.push_back(3); numbers.push_back(4); cout << numbers << endl; return 0; } Be sure to use a destructor to free array! string toString() const { stringstream out; out << "myArray"; for (size_t i = 0; i < size_; ++i) out << ((i % 10) ? " " : "\n") << array_[i]; return out.str(); } friend std::ostream& operator<< (ostream& os, const MyArray<T>& myArray) os << myArray.toString(); return os; Remember, every class needs a toString and a Friend!

17 Step 2 – Template Class Iterators #include <iostream> #include <string> #include <sstream> #define MAX_ARRAY_SIZE using namespace std; template<typename T> class MyArray { private: size_t size_; T* array_; public: MyArray(size_t maxSize) : size_(0) { array_ = (T*)malloc(maxSize * sizeof(T)); } void push_back(T item) { array_[size_++] = item; } }; int main(int argc, char * argv[]) { MyArray<int> numbers(MAX_ARRAY_SIZE); numbers.push_back(1); numbers.push_back(2); numbers.push_back(3); numbers.push_back(4); cout << numbers << endl; return 0; } Templates are a feature of the C++ programming language that allows functions and classes to operate with generic types, allowing a function or class to work on many different data types without being rewritten for each one. There are three kinds of templates: function templates, class templates and, since C++14, variable templates.

18 Step 3 – Add a Nested Iterator
Iterators #include <iostream> #include <string> #include <sstream> #define MAX_ARRAY_SIZE using namespace std; template<typename T> class MyArray { private: size_t size_; T* array_; public: MyArray(size_t maxSize) : size_(0) { array_ = (T*)malloc(maxSize * sizeof(T)); } void push_back(T item) { array_[size_++] = item; } class Iterator size_t index_; Iterator(T* a, size_t s) : array_(a), index_(s) { ... } T& operator[](size_t i) const { return array_[i]; } }; Iterator begin() { return MyArray<T>::Iterator(array_, 0); } Iterator end() { return MyArray<T>::Iterator(array_, size_); } int main(int argc, char * argv[]) { MyArray<int> numbers(MAX_ARRAY_SIZE); numbers.push_back(1); numbers.push_back(2); numbers.push_back(3); numbers.push_back(4); MyArray<int>::Iterator iter = numbers.begin(); for (size_t i = 0; i < 4; ++i) cout << iter[i] << ' '; cout << endl << endl; return 0; } MyArray Iterator Nested classes can access all members of the parent via a reference/pointer.

19 Step 4 – Add Functionality
Iterators #include <iostream> #include <string> #include <sstream> #define MAX_ARRAY_SIZE using namespace std; template<typename T> class MyArray { private: size_t size_; T* array_; public: MyArray(size_t maxSize) : size_(0) { array_ = (T*)malloc(maxSize * sizeof(T)); } void push_back(T item) { array_[size_++] = item; } class Iterator size_t index_; Iterator(T* a, size_t s) : array_(a), index_(s) { ... } T& operator[](size_t i) const { return array_[index_]; } T& operator*() const { ... } Iterator& operator++() { ... } }; Iterator begin() { return MyArray<T>::Iterator(array_, 0); } Iterator end() { return MyArray<T>::Iterator(array_, size_); } int main(int argc, char * argv[]) { MyArray<int> numbers(MAX_ARRAY_SIZE); numbers.push_back(1); numbers.push_back(2); numbers.push_back(3); numbers.push_back(4); MyArray<int>::Iterator iter = numbers.begin(); for (size_t i = 0; i < 4; ++i, ++iter) cout << *iter << ' ‘; cout << endl << endl; return 0; } Add dereference (*) and pre-increment (++) operators.

20


Download ppt "C++ Templates L03 - Iterator 10 – Iterator."

Similar presentations


Ads by Google