//: C09:Database.h // A prototypical resource class. #ifndef DATABASE_H #define DATABASE_H #include <iostream> #include <stdexcept> #include <string> struct DatabaseError : std::runtime_error { DatabaseError(const std::string& msg) : std::runtime_error(msg) {} }; class Database { std::string dbid; public: Database(const std::string& dbStr) : dbid(dbStr) {} virtual ~Database() {} void open() throw(DatabaseError) { std::cout << "Connected to " << dbid << std::endl; } void close() { std::cout << dbid << " closed" << std::endl; } // Other database functions... }; #endif // DATABASE_H ///:~
Listado 8.3. C09/Database.h
//: C09:UseDatabase.cpp #include "Database.h" int main() { Database db("MyDatabase"); db.open(); // Use other db functions... db.close(); } /* Output: connected to MyDatabase MyDatabase closed */ ///:~
Listado 8.4. C09/UseDatabase.cpp
//: C09:Countable.h // A "mixin" class. #ifndef COUNTABLE_H #define COUNTABLE_H #include <cassert> class Countable { long count; protected: Countable() { count = 0; } virtual ~Countable() { assert(count == 0); } public: long attach() { return ++count; } long detach() { return (--count > 0) ? count : (delete this, 0); } long refCount() const { return count; } }; #endif // COUNTABLE_H ///:~
Listado 8.5. C09/Countable.h
//: C09:DBConnection.h // Uses a "mixin" class. #ifndef DBCONNECTION_H #define DBCONNECTION_H #include <cassert> #include <string> #include "Countable.h" #include "Database.h" using std::string; class DBConnection : public Database, public Countable { DBConnection(const DBConnection&); // Disallow copy DBConnection& operator=(const DBConnection&); protected: DBConnection(const string& dbStr) throw(DatabaseError) : Database(dbStr) { open(); } ~DBConnection() { close(); } public: static DBConnection* create(const string& dbStr) throw(DatabaseError) { DBConnection* con = new DBConnection(dbStr); con->attach(); assert(con->refCount() == 1); return con; } // Other added functionality as desired... }; #endif // DBCONNECTION_H ///:~
Listado 8.6. C09/DBConnection.h
//: C09:UseDatabase2.cpp // Tests the Countable "mixin" class. #include <cassert> #include "DBConnection.h" class DBClient { DBConnection* db; public: DBClient(DBConnection* dbCon) { db = dbCon; db->attach(); } ~DBClient() { db->detach(); } // Other database requests using db... }; int main() { DBConnection* db = DBConnection::create("MyDatabase"); assert(db->refCount() == 1); DBClient c1(db); assert(db->refCount() == 2); DBClient c2(db); assert(db->refCount() == 3); // Use database, then release attach from original create db->detach(); assert(db->refCount() == 2); } ///:~
Listado 8.7. C09/UseDatabase2.cpp
//: C09:DBConnection2.h // A parameterized mixin. #ifndef DBCONNECTION2_H #define DBCONNECTION2_H #include <cassert> #include <string> #include "Database.h" using std::string; template<class Counter> class DBConnection : public Database, public Counter { DBConnection(const DBConnection&); // Disallow copy DBConnection& operator=(const DBConnection&); protected: DBConnection(const string& dbStr) throw(DatabaseError) : Database(dbStr) { open(); } ~DBConnection() { close(); } public: static DBConnection* create(const string& dbStr) throw(DatabaseError) { DBConnection* con = new DBConnection(dbStr); con->attach(); assert(con->refCount() == 1); return con; } // Other added functionality as desired... }; #endif // DBCONNECTION2_H ///:~
Listado 8.8. C09/DBConnection2.h
//: C09:UseDatabase3.cpp // Tests a parameterized "mixin" class. #include <cassert> #include "Countable.h" #include "DBConnection2.h" class DBClient { DBConnection<Countable>* db; public: DBClient(DBConnection<Countable>* dbCon) { db = dbCon; db->attach(); } ~DBClient() { db->detach(); } }; int main() { DBConnection<Countable>* db = DBConnection<Countable>::create("MyDatabase"); assert(db->refCount() == 1); DBClient c1(db); assert(db->refCount() == 2); DBClient c2(db); assert(db->refCount() == 3); db->detach(); assert(db->refCount() == 2); } ///:~
Listado 8.9. C09/UseDatabase3.cpp
template<class Mixin1, class Mixin2, ?? , class MixinK> class Subject : public Mixin1, public Mixin2, ?? public MixinK {??};