множество ситуаций, когда требуется, чтобы у класса существовал только один экземпляр. Для этой цели служит шаблон
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 показывает, как можно определить абстрактный класс для чтения настроечного файла.
Пример 8.10. Использование абстрактного базового класса