/* * This demonstrates a toy (in-memory) database to show a use of inheritance. */ #include #include #include #include #include #include #include #include using std::string; using std::make_shared; /* * All database entries. Base class. This class is not technically abstract, * since it contains no abstract functions. But think of it that way. There's * not likely a good reason to instantiate one of these except as part of a * derived class object. */ class DBItem { public: // Construct a new item. DBItem(int code, int qty = 0): m_code(code), m_qty(qty) { } // Obvious extractors and manipulators. int code() const { return m_code; } int qty() const { return m_qty; } void set_qty(int qty) { m_qty = qty; } void inc_qty(int qty) { m_qty += qty; } // Return the item description. Can be replaced. virtual string descr() const { return "Item " + std::to_string(m_code); } protected: const int m_code; // Inventory code number. int m_qty; // Item quantity. }; /* * Coffee maker. Derived from the database object. */ class CoffeeMaker: public DBItem { public: // Create a coffeemaker, with the given inventory code, size (in // cups) and inventory quantity. CoffeeMaker(int code, int ncup, int qty = 0): DBItem(code, qty), m_ncup(ncup) { } // Description. This Is Virtual Regardless of the keyword, since that's // inherited, but useful as documentation. virtual string descr() const override { return "Coffee maker, " + std::to_string(m_ncup) + " cups"; } protected: // Size of the coffee maker. const int m_ncup; }; /* * Monitor. */ class Monitor: public DBItem { public: // Create a monitor with the given inventory code, make, size and // quantity on hand. Monitor(int code, string make, int wdpx, int htpx, int qty = 0): DBItem(code, qty), m_make(make), m_wdpx(wdpx), m_htpx(htpx) { } // Description. virtual string descr() const override { return m_make + " computer monitor " + std::to_string(m_wdpx) + "x" + std::to_string(m_htpx); } protected: // Width and height of the monitor. const int m_wdpx, m_htpx; // Maker. const string m_make; }; /* * CD disk */ class CD: public DBItem { public: // Create a CD object with the given inventory code, artist and // title, and quantity on hand. CD(int code, const string &artist, const string &title, int qty = 0): DBItem(code, qty), m_artist(artist), m_title(title) { } // Description. virtual string descr() const override { return m_artist + ": " + m_title + " (CD)"; } protected: // CD artist and title. const string m_artist, m_title; }; /* * There should be a standard library utility for this. */ string downcase(string str) { for(char &c: str) { c = tolower(c); } return str; } /* * Trim punctuation. */ string trim(string str) { while(str.size() > 0 && !isalnum(str[0])) { str.erase(0,1); } while(str.size() > 0 && !isalnum(str.end()[-1])) { str.erase(str.end()-1); } return str; } /* * Place a few items into our inventory then support searches. */ int main(int argc, char **argv) { // This will serv as our toy inventory database. The data items must be // pointers to the base class. Collections are homogeneous, so // we can't put different types of things into one, but we can // make a collection of the base class pointers, and have some of // them point to derived objects. std::map> db; // Put some random items into the database. When you put all the items in one list // it won't compile because their types differ. I think this is fixable, but three loops // works fine. for(auto &i: { make_shared(1872, 12, 10), make_shared(1880, 12, 8), make_shared(1810, 8, 3), make_shared(1110, 8, 10) }) { db[i->code()] = i; } for(auto &i: { make_shared(4715, "HP", 1600, 900, 0), make_shared(4499, "HP", 1920, 1200, 10), make_shared(4412, "Dell", 1920, 1200, 10), make_shared(4711, "Dell", 800, 600, 47), make_shared(4021, "HP", 1920, 1080, 10), make_shared(4631, "Samsung", 1920, 1080, 10) }) { db[i->code()] = i; } for(auto &i: { make_shared(3812, "Pink Floyd", "Dark Side of the Moon", 5), make_shared(3216, "Mannheim Steamroller", "Fresh Aire V", 21), make_shared(3012, "Nick Drake", "Five Leaves Left", 10), make_shared(3887, "October Project", "Falling Farther In", 8), make_shared(3781, "Dar Williams", "The Beauty of the Rain", 0), make_shared(3731, "The Left Banke", "There's Gonna Be A Storm", 18) }) { db[i->code()] = i; } // Build a word index. This uses a multimap, which allows multiple // entries for a key. The keys will be words from the descriptions. std::multimap index; for(auto &pair: db) { // Each pair is a key, value from the map. std::istringstream in(pair.second->descr()); string word; while(in >> word) { word = trim(downcase(word)); if(word.size() > 1 && word != "of" && word != "the") index.insert(std::make_pair(word, pair.first)); } } // Run searches. std::cout << "Find: "; string word; while(std::cin >> word) { // If you forgot ^d. if(word == "quit") { exit(0); } // The function returns a range of matches. May be more than one in a // multimap auto range = index.equal_range(trim(downcase(word))); if(range.first == range.second) { std::cout << word << " not found" << std::endl; } else { // Scan the range of matches. Each are in the // index, where the second item is the inventory // number used to look up the item record. for(auto i = range.first; i != range.second; ++i) { // Get the database item from the stock number in the index. auto itm = db.find(i->second)->second; // Print a description. std::cout << itm->code() << " " << itm->descr() << std::endl; if(itm->qty() == 0) { std::cout << " Out of stock"; } else { std::cout << " " << itm->qty() << " in stock"; } std::cout << std::endl; } } std::cout << "Find: "; } }