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

Any static member object inside a class is an expression of Singleton: one and only one will be made. So in a sense, the language has direct support for the idea; we certainly use it on a regular basis. However, a problem is associated with static objects (member or not), and that’s the order of initialization, as described in Volume 1 of this book. If one static object depends on another, it’s important that the objects are initialized in the correct order.

In Volume 1, you were shown how to control initialization order by defining a static object inside a function. This delays the initialization of the object until the first time the function is called. If the function returns a reference to the static object, it gives you the effect of a Singleton while removing much of the worry of static initialization. For example, suppose you want to create a log file upon the first call to a function that returns a reference to that log file. This header file will do the trick:

//: C10:LogFile.h

#ifndef LOGFILE_H

#define LOGFILE_H

#include

std::ofstream& logfile();

#endif // LOGFILE_H ///:~

The implementation must not be inlined, because that would mean that the whole function, including the static object definition within, could be duplicated in any translation unit where it’s included, which violates C++’s one-definition rule.[117] This would most certainly foil the attempts to control the order of initialization (but potentially in a subtle and hard-to-detect fashion). So the implementation must be separate:

//: C10:LogFile.cpp {O}

#include "LogFile.h"

std::ofstream& logfile() {

  static std::ofstream log("Logfile.log");

  return log;

} ///:~

Now the log object will not be initialized until the first time logfile( ) is called. So if you create a function:

//: C10:UseLog1.h

#ifndef USELOG1_H

#define USELOG1_H

void f();

#endif // USELOG1_H ///:~

that uses logfile() in its implementation:

//: C10:UseLog1.cpp {O}

#include "UseLog1.h"

#include "LogFile.h"

void f() {

  logfile() << __FILE__ << std::endl;

} ///:~

And you use logfile() again in another file:

//: C10:UseLog2.cpp

//{L} LogFile UseLog1

#include "UseLog1.h"

#include "LogFile.h"

using namespace std;

void g() {

  logfile() << __FILE__ << endl;

}

int main() {

  f();

  g();

} ///:~

the log object doesn’t get created until the first call to f( ).

You can easily combine the creation of the static object inside a member function with the Singleton class. SingletonPattern.cpp can be modified to use this approach:[118] 

//: C10:SingletonPattern2.cpp

// Meyers’ Singleton

#include

using namespace std;

class Singleton {

  int i;

  Singleton(int x) : i(x) { }

  void operator=(Singleton&);

  Singleton(const Singleton&);

public:

  static Singleton& instance() {

    static Singleton s(47);

    return s;

  }

  int getValue() { return i; }

  void setValue(int x) { i = x; }

};

int main() {

  Singleton& s = Singleton::instance();

  cout << s.getValue() << endl;

  Singleton& s2 = Singleton::instance();

  s2.setValue(9);

  cout << s.getValue() << endl;

} ///:~

An especially interesting case occurs if two Singletons depend on each other, like this:

//: C10:FunctionStaticSingleton.cpp

class Singleton1 {

  Singleton1() {}

public:

  static Singleton1& ref() {

    static Singleton1 single;

    return single;

  }

};

class Singleton2 {

  Singleton1& s1;

  Singleton2(Singleton1& s) : s1(s) {}

public:

  static Singleton2& ref() {

    static Singleton2 single(Singleton1::ref());

    return single;

  }

  Singleton1& f() { return s1; }

};

int main() {

  Singleton1& s1 = Singleton2::ref().f();

} ///:~

When Singleton2::ref( ) is called, it causes its sole Singleton2 object to be created. In the process of this creation, Singleton1::ref( ) is called, and that causes the sole Singleton1 object to be created. Because this technique doesn’t rely on the order of linking or loading, the programmer has much better control over initialization, leading to fewer problems.

Yet another variation on Singleton allows you to separate the "Singleton-ness" of an object from its implementation. This is achieved through templates, using the Curiously Recurring Template Pattern mentioned in Chapter 5.

//: C10:CuriousSingleton.cpp

// Separates a class from its Singleton-ness (almost)

#include

using namespace std;

template

class Singleton {

public:

  static T& instance() {

    static T theInstance;

    return theInstance;

  }

protected:

  Singleton() {}

  virtual ~Singleton() {}

private:

  Singleton(const Singleton&);

  Singleton& operator=(const Singleton&);

};

// A sample class to be made into a Singleton

class MyClass : public Singleton {

  int x;

protected:

  friend class Singleton;

  MyClass(){x = 0;}

public:

  void setValue(int n) { x = n; }

  int getValue() const { return x; }

};

int main() {

  MyClass& m = MyClass::instance();

  cout << m.getValue() << endl;

  m.setValue(1);

  cout << m.getValue() << endl;

} ///:~

MyClass is made a Singleton by:

1.       Making its constructor private or protected.

2.      Making Singleton a friend.

3.      Deriving MyClass from Singleton.

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

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

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

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

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

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

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

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

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