Читаем 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;

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

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

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

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