Generalized Collection Printer
// There is a standard vector class in C++, but it is based on a // template, not on polymophism. #include <iostream> #include <vector> #include <list> #include <string> using namespace std; // Generic printing function. Note: This function can print the contents // of any object which implements the iterator pattern used by the standard // library, and whose members cout knows how to print. template <typename CollectType> void print_col(CollectType &v) { int m = 0; for(auto i = v.begin(); i != v.end(); ++i) { if(i != v.begin()) cout << " "; cout << *i; } } void craziness(); int main() { // Put some stuff in a vector of strings. vector<string> v = { "How", "are", "you", "today?" }; v.insert(v.begin() + 3, "doing"); print_col(v); cout << endl; // Put some stuff in a list. list<int> q; q.push_back(45); q.push_back(3); q.push_front(-34); q.push_back(75); q.push_front(9); print_col(q); cout << endl; // And try a string, which also offers the iterator pattern. string mars = "Hello, Mars!"; print_col(mars); cout << endl; // See below. If you dare. craziness(); } // ==== Consider the rest of this file optional material ==== /* * This class represents a range that can be iterated through. Not good for * much, though I suppose it could be the start of something marginally * useful. */ class Range { public: // Range of numbers is first to last. Range(int first, int last) { set(first, last); } // Change the range. void set(int first, int last) { m_first = first; m_last = last; } // This is the iterator type, which is really just a // wrapper for int. This class uses the operator keyword which // allows a C++ programmer to define methods which give the meaning // of certain operators. It should be used sparingly, but some are // required to create an iterator. class iterator { public: iterator(int i) { m_i = i; } // This defines the meaning of the ++ operator on an iterator. iterator operator++() { ++m_i; return *this; } // Here's what * does to an iterator. (Just returns // the integer.) int operator*() const { return m_i; } // Define how to compare. int operator!=(iterator i) const { return m_i != i.m_i; } private: int m_i; }; // Begin and end. iterator begin() { return iterator(m_first); } iterator end() { return iterator(m_last + 1); } private: // The start and end of the range. int m_first, m_last; }; void craziness() { Range ct(1,10); print_col(ct); cout << endl; ct.set(6,18); print_col(ct); cout << endl; }

This is similar, but the type parameter is assumed to be something which implements the iterator pattern. This includes any of the standard collections, but can also include classes you define to implement the pattern. This fact is not declared anywhere, but is implicit in the code, and will be enforced if you try to print a class that doesn't have the needed type and operations.

The actual implementation of the iterator pattern requires some features we haven't discussed, as shown in the Range class at the bottom of the file.