Чтение онлайн

ЖАНРЫ

C++. Сборник рецептов

Когсуэлл Джефф

Шрифт:

UniqueID::UniqueID(const UniqueID& orig) {

 id = orig.id;

}

UniqueID& UniqueID::operator=(const UniqueID& orig) {

 id = orig.id;

 return(*this);

}

Но может возникнуть ситуация, когда в контексте приложения будет иметь смысл создать для объекта в контейнере новое уникальное значение. В этом случае просто снова используйте статическую переменную, как это сделано в обычном конструкторе и показано здесь.

UniqueID::UniqueID(const UniqueID& orig) {

 id = ++nextID;

}

UniqueID& UniqueID::operator=(const UniqueID& orig) {

 id = ++nextID;

 return(*this);

}

Однако

трудности еще не закончились. Если
UniqueID
будет использоваться несколькими потоками, у вас снова возникнут проблемы, так как доступ к статическим переменным не синхронизирован. За дополнительной информацией о работе с ресурсами при наличии нескольких потоков обратитесь к главе 12.

Смотри также

Рецепт 8.3.

8.9. Создание Singleton-класса

Проблема

Имеется класс, который должен иметь только один экземпляр, и требуется предоставить способ доступа к этому классу из клиентского кода таким образом, чтобы каждый раз возвращался именно этот единственный объект. Часто это называется шаблоном singleton или singleton-классом.

Решение

Создайте статический член, который указывает на текущий класс, ограничьте использование конструкторов для создания класса, сделав их

private
, и создайте открытую статическую функцию-член, которая будет использоваться для доступа к единственному статическому экземпляру. Пример 8.9 демонстрирует, как это делается.

Пример 8.9. Создание singleton-класса

#include <iostream>

using namespace std;

class Singleton {

public:

 // С помощью этого клиенты получат доступ к единственному экземпляру

 static Singleton* getInstance;

 void setValue(int val) {value_ = val;}

 int getValue {return(value_);}

protected:

 int value_;

private:

 static Singleton* inst_; // Единственный экземпляр

 Singleton : value_(0) {} // частный конструктор

 Singleton(const Singleton&);

 Singleton& operator=(const Singleton&);

};

// Определяем указатель

static Singleton Singleton* Singleton::inst_ = NULL;

Singleton* Singleton::getInstance {

 if (inst_ == NULL) {

inst_ = new Singleton;

 }

 return(inst_);

}

int main {

 Singleton* p1 = Singleton::getInstance;

 p1->setValue(10);

 Singleton* p2 = Singleton::getInstance;

 cout << "Value = " << p2->getValue << '\n';

}

Обсуждение

Существует

множество ситуаций, когда требуется, чтобы у класса существовал только один экземпляр. Для этой цели служит шаблон
Singleton
. Выполнив несколько простых действий, можно реализовать singleton-класс в С++.

Когда принимается решение, что требуется только один экземпляр чего-либо, то на ум сразу должно приходить ключевое слово

static
. Как было сказано в рецепте 8.5, переменная-член
static
— это такая, которая может иметь в памяти только один экземпляр. Для отслеживания единственного объекта singleton-класса используйте переменную-член
static
, как сделано в примере 8.9.

private:

 static Singleton* inst_;

Чтобы клиентский код ничего про нее не знал, сделайте ее

private
. Убедитесь, что в файле реализации она проинициализирована значением
NULL
.

Singleton* Singleton::inst_ = NULL;

Чтобы запретить клиентам создавать экземпляры этого класса, сделайте конструкторы

private
, особенно конструктор по умолчанию.

private:

Singleton {}

Таким образом, если кто-то попробует создать в куче или стеке новый singleton-класс, то он получит дружественную ошибку компилятора.

Теперь, когда статическая переменная для хранения единственного объекта

Singleton
создана, создание объектов
Singleton
ограничено с помощью ограничения конструкторов; все, что осталось сделать, — это предоставить клиентам способ доступа к единственному экземпляру объекта
Singleton
. Это делается с помощью статической функции-члена.

Singleton* Singleton::getInstance {

 if (inst_ == NULL) {

inst_ = new Singleton;

 }

 return(inst_);

}

Посмотрите, как это работает. Если указатель

static Singleton
равен
NULL
, создается объект. Если он уже был создан, то возвращается его адрес. Клиенты могут получить доступ к экземпляру
Singleton
, вызвав его статический метод.

Singleton* p1 = Singleton::getInstance;

И если вы не хотите, чтобы клиенты работали с указателями, то можно возвращать ссылку.

Singleton& Singleton::getInstance {

 if (inst_ == NULL) {

inst_ = new Singleton;

 }

 return(*inst_);

}

Важно здесь то, что в обоих случаях клиентам запрещено создавать экземпляры объекта

Singleton
, и создается единый интерфейс, который предоставляет доступ к единственному экземпляру.

Поделиться с друзьями: