#include "SWindows.h" // set up for windows #include "IOTools.h" // tools for safe I/O // so far the Table can consist only of Records. It is possible // to modify Table so that it takes any kind of class for its elements. // Such a parametrized Table is done with templates , which are the // right and the only way to create a container like Table . struct Record { string name; int value; Record() { cout << "Creating a record\n"; } ~Record() { cout << "Destroying a record\n"; } }; class Table { // this is a SELF-EXPANDING table of records private: int capacity; int idx; Record * table; Table( const Table & ); // no one can copy our objects: // no void foo( Table t ); -- this needs to // call the copy contructor, which is hereby // made private, no Table a =b; no Table a(b); void operator=( const Table & ); // no one can assign to our objects: // no a = b; public: Table ( int init_capacity = 2 ); // initially, the table will be able // to hold just two entries ~Table (); void Add( const string & n, int value ); int Find( const string & n ); // overloaded subsript operator, // two versions for const and non-const objects Record& operator[] (int index ); Record operator[] const (int index ); void Print(); }; // end of Table definition Table::Table( int init_capacity ) : capacity( init_capacity ), idx(0) { cout << "Creating a table... Capacity is " << capacity << endl; table = new Record [ init_capacity ]; //calls Record() that many times } Table::~Table(){ delete[ ] table; } // must ecplicitly "delete" anything // allocated with "new" // returning a reference to a table record enables assignment to table // entries Record& Table::operator[] (int index ){ if( index >= idx || idx < 0 ) { cerr << "Invalid index in Table::operator[]. Aborting program.\n"; exit(-1); } return table[index]; } // this variant is for objects passed as const reference that cannot be // changed (in particular, cannot stand on the LHS of an assignment) Record Table::operator[] const (int index ){ if( index >= idx || idx < 0 ) { cerr << "Invalid index in Table::operator[] const. Aborting program.\n"; exit(-1); } return table[index]; } void Table::Add( const string& n, int r ){ // currently we have "idx" entries // if any unoccupied records remain from the previous allocation, // simple take the record number "idx" // If not: reallocate the memory array in which the values are stored if( idx == capacity ){ // allocate new memory Record * new_table = new Record[ capacity*2 ]; // copy old table over for( int i=0; i < capacity; i++ ) new_table[i] = table[i]; delete[ ] table; // delete old table = new_table; // pointer assignment, nothing get copied in // the memory, but table is now pointing at a // different (larger) chunk of memory capacity *= 2; cout << "Reallocated memory... Capacity is now " << capacity << endl; } // slot "idx" is the next free slot; we know that it is free. Fill it now. table[ idx ].name = n; table[ idx ].value = r; idx++; } void Table::Print(){ for(int i=0; i " << table[i].value << endl; // This should be cout << table[i] << endl; -- // Record must be smart enough to print itself. // this can be done by overloading << for Record cout << idx << " entries total\n"; } // write your own function Find, to find a value by the title, // or signal error if the name is not in the tabble void main() { BigConsole(); // open text and drawing windows Table movies; string s = ""; int r; while(true){ // continue the loop until we break cout << "Enter a title ('bye' to finish) : "; getline( cin, s ); if( s == "bye" ) break; cout << "Enter its value: "; cin >> r; movies.Add( s, r ); } cout << "We now have:\n"; movies.Print(); bool b; cout << "\nTesting []. Invalid index forces exit. \n" << endl; // input record numbers and print out and then modify its contents. PressReturn("Done!"); }