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

class CountedClass {

  static int count;

public:

  CountedClass() { ++count; }

  CountedClass(const CountedClass&) { ++count; }

  ~CountedClass() { --count; }

  static int getCount() { return count; }

};

int CountedClass::count = 0;

int main() {

  CountedClass a;

  cout << CountedClass::getCount() << endl;   // 1

  CountedClass b;

  cout << CountedClass::getCount() << endl;   // 2

  { // an arbitrary scope:

    CountedClass c(b);

    cout << CountedClass::getCount() << endl; // 3

    a = c;

    cout << CountedClass::getCount() << endl; // 3

  }

  cout << CountedClass::getCount() << endl;   // 2

} ///:~.

All constructors of CountedClass increment the static data member count, and the destructor decrements it. The static member function getCount( ) yields the number of current objects whenever it called.

It would be tremendously tedious to have to manually add these members every time you wanted to add object counting to a class. What is the usual object-oriented device to which one turns to repeat or share code? It’s inheritance, of course, which, unfortunately, is only half a solution in this case. Observe what happens when we collect the counting logic into a base class.

//: C05:CountedClass2.cpp

// Erroneous attempt to count objects

#include

using namespace std;

class Counted {

  static int count;

public:

  Counted() { ++count; }

  Counted(const Counted&) { ++count; }

  ~Counted() { --count; }

  static int getCount() { return count; }

};

int Counted::count = 0;

class CountedClass : public Counted {};

class CountedClass2 : public Counted {};

int main() {

  CountedClass a;

  cout << CountedClass::getCount() << endl;    // 1

  CountedClass b;

  cout << CountedClass::getCount() << endl;    // 2

  CountedClass2 c;

  cout << CountedClass2::getCount() << endl;   // 3 (Error)

} ///:~

All classes that derive from Counted share the same, single static data member, so the number of objects is tracked collectively across all classes in the Counted hierarchy. What is needed is a way to automatically generate a different base class for each derived class. This is accomplished by the curious template construct illustrated below:.

//: C05:CountedClass3.cpp

#include

using namespace std;

template

class Counted {

  static int count;

public:

  Counted() { ++count; }

  Counted(const Counted&) { ++count; }

  ~Counted() { --count; }

  static int getCount() { return count; }

};

template

int Counted::count = 0;

// Curious class definitions

class CountedClass : public Counted {};

class CountedClass2 : public Counted {};

int main() {

  CountedClass a;

  cout << CountedClass::getCount() << endl;    // 1

  CountedClass b;

  cout << CountedClass::getCount() << endl;    // 2

  CountedClass2 c;

  cout << CountedClass2::getCount() << endl;   // 1 (!)

} ///:~.

Each derived class derives from a unique base class that is determined by using itself (the derived class) as a template parameter! This may seem like a circular definition, and it would be, had any base class members used the template argument in a computation. Since all data members of Counted are not dependent on T, its size (which is zero!) is known when the template is parsed. It doesn’t matter, therefore, which argument is used to instantiate Counted; its size is always the same. Therefore, any derivation from an instance of Counted can be completed when it is parsed, and there is no recursion. Since each base class is unique, it has its own static data, thus constituting a handy technique for adding counting to any class whatsoever. Jim Coplien was the first to mention this interesting derivation idiom in print, which he cited in an article, entitled "Curiously Recurring Template Patterns."[ ][65] 

<p>Template metaprogramming</p>

In 1993 compilers were beginning to support simple template constructs so that users could define generic containers and functions. About the same time that the STL was being considered for adoption into standard C++, clever and surprising examples such as the following were passed around among members of the standards committee:.

//: C05:Factorial.cpp

// Compile-time computation!

#include

using namespace std;

template

struct Factorial {

   enum {val = Factorial::val * n};

};

template<>

struct Factorial<0> {

   enum {val = 1};

};

int main() {

   cout << Factorial<12>::val << endl; // 479001600

} ///:~

That this program prints the correct value of 12! is not alarming. What is alarming is that the computation is complete before the program even runs!.

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

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

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

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

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

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

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

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

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