Bruce Eckel's Thinking in C++, 2nd Ed | Contents | Prev | Next |
//: CXX:Bicycle.h // Complex class involving dynamic aggregation #ifndef BICYCLE_H #define BICYCLE_H #include <vector> #include <string> #include <iostream> #include <typeinfo> class LeakChecker { int count; public: LeakChecker() : count(0) {} void print() { std::cout << count << std::endl; } ~LeakChecker() { print(); } void operator++(int) { count++; } void operator--(int) { count--; } }; class BicyclePart { static LeakChecker lc; public: BicyclePart() { lc++; } virtual BicyclePart* clone() = 0; virtual ~BicyclePart() { lc--; } friend std::ostream& operator<<(std::ostream& os, BicyclePart* bp) { return os << typeid(*bp).name(); } friend class Bicycle; }; enum BPart { Frame, Wheel, Seat, HandleBar, Sprocket, Deraileur, }; template<BPart id> class Part : public BicyclePart { public: BicyclePart* clone() { return new Part<id>; } }; class Bicycle { public: typedef std::vector<BicyclePart*> VBP; Bicycle(); Bicycle(const Bicycle& old); Bicycle& operator=(const Bicycle& old); // [Other operators as needed go here:] // [...] // [...] ~Bicycle() { purge(); } // So you can change parts on a bike (but be // careful: you must clean up any objects you // remove from the bicycle!) VBP& bikeParts() { return parts; } friend std::ostream& operator<<(std::ostream& os, Bicycle* b); static void print(std::vector<Bicycle*>& vb, std::ostream& os = std::cout); private: static int counter; int id; VBP parts; void purge(); }; // Both the Bicycle and the generator should // provide more variety than this. But this gives // you the idea. struct BicycleGenerator { Bicycle* operator()() { return new Bicycle(); } }; #endif // BICYCLE_H ///:~
//: CXX:Bicycle.cpp {O} // Bicycle implementation #include <map> #include <algorithm> #include <cassert> #include "Bicycle.h" using namespace std; // Static member definitions: LeakChecker BicyclePart::lc; int Bicycle::counter = 0; Bicycle::Bicycle() : id(counter++) { BicyclePart *bp[] = { new Part<Frame>, new Part<Wheel>, new Part<Wheel>, new Part<Seat>, new Part<HandleBar>, new Part<Sprocket>, new Part<Deraileur>, }; const int bplen = sizeof bp / sizeof *bp; parts = VBP(bp, bp + bplen); } Bicycle::Bicycle(const Bicycle& old) : parts(old.parts.begin(), old.parts.end()) { for(int i = 0; i < parts.size(); i++) parts[i] = parts[i]->clone(); } Bicycle& Bicycle::operator=(const Bicycle& old) { purge(); // Remove old lvalues parts.resize(old.parts.size()); copy(old.parts.begin(), old.parts.end(), parts.begin()); for(int i = 0; i < parts.size(); i++) parts[i] = parts[i]->clone(); return *this; } void Bicycle::purge() { for(VBP::iterator it = parts.begin(); it != parts.end(); it++) { delete *it; *it = 0; // Prevent multiple deletes } } ostream& operator<<(ostream& os, Bicycle* b) { copy(b->parts.begin(), b->parts.end(), ostream_iterator<BicyclePart*>(os, "\n")); os << "--------" << endl; return os; } void Bicycle::print(vector<Bicycle*>& vb, ostream& os) { copy(vb.begin(), vb.end(), ostream_iterator<Bicycle*>(os, "\n")); cout << "--------" << endl; } ///:~
//: CXX:BikeTest.cpp //{L} Bicycle #include "Bicycle.h" #include <algorithm> using namespace std; int main() { vector<Bicycle*> bikes; BicycleGenerator bg; generate_n(back_inserter(bikes), 12, bg); Bicycle::print(bikes); } ///:~