Читаем Thinking In C++. Volume 2: Practical Programming полностью

    DBConnection* con = new DBConnection(dbStr);

    con->attach();

    assert(con->refCount() == 1);

    return con;

  }

// Other added functionality as desired...

protected:

  DBConnection(const string& dbStr) throw(DatabaseError)

  : Database(dbStr) {

    open();

  }

  ~DBConnection() {

    close();

  }

private:

  // Disallow copy

  DBConnection(const DBConnection&);

  DBConnection& operator=(const DBConnection&);

};

#endif ///:~

We now have a reference-counted database connection without modifying the Database class, and we can safely assume that it will not be surreptitiously terminated. The opening and closing is done using the Resource Acquisition Is Initialization idiom (RAII) mentioned in Chapter 1 via the DBConnection constructor and destructor. This makes using a DBConnection easy to use, as the following program shows.

//: C09:UseDatabase2.cpp

// Tests the Countable "mixin" class

#include

#include "DBConnection.h"

class DBClient {

public:

  DBClient(DBConnection* dbCon) {

    db = dbCon;

    db->attach();

  }

  ~DBClient() {

    db->detach();

  }

  // Other database requests using db…

private:

  DBConnection* 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);

} ///:~

The call to DBConnection::create( ) calls attach( ), so when we’re finished, we must explicitly call detach( ) to release the original hold on the connection. Note that the DBClient class also uses RAII to manage its use of the connection. When the program terminates, the destructors for the two DBClient objects will decrement the reference count (by calling detach( ), which DBConnection inherited from Countable), and the database connection will be closed when the count reaches zero after the object c1 is destroyed. (This is because of Countable’s virtual destructor, as we explained earlier.)

A template approach is commonly used for mixin inheritance, allowing the user to specify at compile time which flavor of mixin is desired. This way you can use different reference-counting approaches without explicitly defining DBConnection twice. Here’s how it’s done.

//: C09:DBConnection2.h

// A parameterized mixin

#ifndef DBCONNECTION_H

#define DBCONNECTION_H

#include "Database.h"

#include

#include

using std::string;

template

class DBConnection : public Database, public Counter {

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...

protected:

  DBConnection(const string& dbStr) throw(DatabaseError)

  : Database(dbStr) {

    open();

  }

  ~DBConnection() {

    close();

  }

private:

  // Disallow copy

  DBConnection(const DBConnection&);

  DBConnection& operator=(const DBConnection&);

};

#endif ///:~

The only change here is the template prefix to the class definition (and renaming Countable to Counter for clarity). We could also make the database class a template parameter (had we multiple database access classes to choose from), but it is not a mixin, per se, since it is a standalone class. The following example uses the original Countable as the Counter mixin type, but we could use any type that implements the appropriate interface (attach( ), detach( ), and so on).

//: C09:UseDatabase3.cpp

// Tests a parameterized "mixin" class

#include

#include "Countable.h"

#include "DBConnection2.h"

class DBClient {

public:

  DBClient(DBConnection* dbCon) {

    db = dbCon;

    db->attach();

  }

  ~DBClient() {

    db->detach();

  }

private:

  DBConnection* 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);

  db->detach();

  assert(db->refCount() == 2);

} ///:~

The general pattern for multiple parameterized mixins is simply:

template

class Subject : public Mixin1,

 public Mixin2,

 …

                public MixinK {..};

<p>Duplicate subobjects</p>

When you inherit from a base class, you get a copy of all the data members of that base class in your derived class. The following program shows how multiple base subobjects might be laid out in memory.[108] 

//: C09:Offset.cpp

// Illustrates layout of subobjects with MI

#include

using namespace std;

class A {

  int x;

};

class B {

  int y;

};

class C : public A, public B {

  int z;

};

int main() {

  cout << "sizeof(A) == " << sizeof(A) << endl;

  cout << "sizeof(B) == " << sizeof(B) << endl;

  cout << "sizeof(C) == " << sizeof(C) << endl;

  C c;

  cout << "&c == " << &c << endl;

  A* ap = &c

  B* bp = &c

  cout << "ap == " << static_cast(ap) << endl;

  cout << "bp == " << static_cast(bp) << endl;

  C* cp = static_cast(bp);

  cout << "cp == " << static_cast(cp) << endl;

Перейти на страницу:

Похожие книги

3ds Max 2008
3ds Max 2008

Одни уверены, что нет лучшего способа обучения 3ds Мах, чем прочитать хорошую книгу. Другие склоняются к тому, что эффективнее учиться у преподавателя, который показывает, что и как нужно делать. Данное издание объединяет оба подхода. Его цель – сделать освоение 3ds Мах 2008 максимально быстрым и результативным. Часто после изучения книги у читателя возникают вопросы, почему не получился тот или иной пример. Видеокурс – это гарантия, что такие вопросы не возникнут: ведь автор не только рассказывает, но и показывает, как нужно работать в 3ds Мах.В отличие от большинства интерактивных курсов, где работа в 3ds Мах иллюстрируется на кубиках-шариках, данный видеокурс полностью практический. Все приемы работы с инструментами 3ds Мах 2008 показаны на конкретных примерах, благодаря чему после просмотра курса читатель сможет самостоятельно выполнять даже сложные проекты.

Владимир Антонович Верстак , Владимир Верстак

Программирование, программы, базы данных / Программное обеспечение / Книги по IT