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() << '
';
}
Существует множество ситуаций, когда требуется, чтобы у класса существовал только один экземпляр. Для этой цели служит шаблон 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
, и создается единый интерфейс, который предоставляет доступ к единственному экземпляру.
Рецепт 8.3.
8.10. Создание интерфейса с помощью абстрактного базового класса
Требуется определить интерфейс, который будет реализовываться производными классами, но концепция этого интерфейса является абстракцией и не должна наследоваться сама по себе.
Создайте абстрактный класс, который определяет интерфейс, объявляя, по крайней мере, одну из своих функций как чисто виртуальную (virtual
). Создайте классы, производные от этого абстрактного класса, которые будут использовать различные реализации, обеспечивая при этом один и тот же интерфейс. Пример 8.10 показывает, как можно определить абстрактный класс для чтения настроечного файла.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class AbstractConfigFile {
public:
virtual ~AbstractConfigFile() {}
virtual void getKey(const string& header,
const string& key, strings val) const = 0;
virtual void exists(const string& header,
const string& key, strings val) const = 0;
};
class TXTConfigFile : public AbstractConfigFile {
public:
TXTConfigFile() : in_(NULL) {}