Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Уникальный экземпляр класса

27K
12 августа 2007 года
korisk
12 / / 11.08.2007
Доброго времени суток, уважаемые специалисты.
Вопрос 1:

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

Вопрос 2:
Для динамического создания такого объекта достаточно переопределить операторы new и delete класса.Или я в чем-то ошибаюсь?

Спасибо за внимание
11K
12 августа 2007 года
Free Thinker
118 / / 16.03.2007
на C# это называется singleton. вот пример:

Код:
class Singleton
{
    private Singleton() {}
    private static Singleton _instance;

    public static Singleton Instance()
    {
        lock(typeof(Singleton))
        {
             if(_instance == null)
                 _instance = new Singleton();
        }
        return _instance;
     }
}


или проще:

 
Код:
sealed class Singleton
{
     private Singleton() {}

     public static readonly Singleton Instance = new Singleton();
}


на эту тему можно найти кучу примеров. поищи на "C# singleton".
240
12 августа 2007 года
aks
2.5K / / 14.07.2006
Free Thinker, singleton это паттерн проектирования для ООП впринципе, а не для конкретно C# =)
11K
12 августа 2007 года
Free Thinker
118 / / 16.03.2007
спасибо, бум знать. просто я им только на C# пользовался.
350
12 августа 2007 года
cheburator
589 / / 01.06.2006
Код:
// Файл myclass.h

class MyClass
{
public:
    void *operator new (size_t);
    void operator delete (void*);
    void *operator new[] (size_t);
    void operator delete[] (void*);
private:
    static MyClass *singleton;
};

// Файл myclass.cpp
#include "myclass.h"

MyClass *MyClass::singleton = 0;

void *MyClass::operator new (size_t)
{
    if (MyClass::singleton == 0)
        singleton = ::new MyClass;
    return singleton;
};

void MyClass::operator delete (void*)
{
    if (singleton == 0)  // Надо вызвать некое исключение (замените строку ниже на нужное исключение)
        throw 1;
    delete MyClass::singleton;
    MyClass::singleton = 0;
};

void *MyClass::operator new[] (size_t)
{
    // Замените строку на нужное исключение
    throw 1;
};

void MyClass::operator delete[] (void*)
{
    // Замените строку на нужное исключение
    throw 1;
};

Операторы new[] и delete[] перегружены только для того, чтобы пользователь ими не пользовался - в случае использования генерируется исключение.
Есть более "красивый" способ - декларировать эти операторы, но не реализовать, т. е. выкинуть соответствующий код из myclass.cpp.
Тогда попытка использования new[] и delete[] будет пресекаться еще во время компиляции.
350
12 августа 2007 года
cheburator
589 / / 01.06.2006
P. S.
По идее, нужно добавить счетчик ссылок, чтобы программа могла вызывать new многократно и столько же раз потом вызывать delete. Для этого, добавляем в класс статический член - счетчик:
 
Код:
class MyClass
{
...
    static size_t singleton_count;
}

И myclass.cpp должен выглядеть примерно так:
Код:
#include "myclass.h"

MyClass *MyClass::singleton = 0;
size_t MyClass::singleton_count = 0;

void *MyClass::operator new (size_t)
{
    if (MyClass::singleton_count == 0)
        singleton = ::new MyClass;
    ++MyClass::singleton_count;
    return singleton;
};

void MyClass::operator delete (void*)
{
    if (MyClass::singleton_count == 0)
        throw 1;
    if (--MyClass::singleton_count == 0)
        delete MyClass::singleton;
    MyClass::singleton = 0;
};

Другой способ - вообще запретить многократный вызов new.
350
12 августа 2007 года
cheburator
589 / / 01.06.2006
Еще способ попроще - создать экземпляр класса сразу, и не пользоваться вообще new и delete, а просто описать какой-то метод, который бы возвращал пользователю ссылку на экземпляр.
Для этого следует запретить new и delete, конструктор и деструктор сделать приватными.
Код:
// Файл MyClass2.h
class MyClass2
{
public:
    void *operator new (size_t);  // Операторы объявляем, но не реализуем
    void operator delete (void*);
    void *operator new[] (size_t);
    void operator delete[] (void*);
    MyClass2 &get () { return singleton; };
private:
    MyClass2();  // При желании добавить параметры
    ~MyClass2();
    static MyClass2 singleton;
};

// Файл MyClass2.cpp
#include "myclass2.h"
MyClass2 MyClass2::singleton; // При желании добавить параметры (в скобках)

Отличие такого способа от перегрузки new/delete в том, что экземпляр класса создается сразу при старте программы и уничтожается при ее завершении. Если экземпляр класса должен, например, создаваться не ранее какого-то момента, а уничтожаться не позднее какого-то, такой способ не годится.
---
Рекомендую книгу:
Э. Гамма, Р. Хелм и др.
Приемы объектно-ориентированного проектирования. Паттерны проектирования.
Стр. 130. Паттерн Singleton
3
12 августа 2007 года
Green
4.8K / / 20.01.2000
Зачем, вообще, объявлять операторы new/delete?
Достаточно просто сделать приватными конструктор/деструктор.
Кстати, в.т.ч. и конструктор копирования.

Зачем создавать экземпляр на старте?
Его вполне можно создать при первой необходимости, например, при первом к нему обращении.

Все значительно проще:
Код:
class Singleton
{
public:
    static Singleton& getInstance() {
        if(_instance == NULL) {
            _instance = new Singleton;
        }
        return *_instance;
    }

private:
    Singleton();
    Singleton(const Singleton&);
    ~Singleton();

    static Singleton* _instance;
};

Singleton* Singleton::_instance = NULL;
350
13 августа 2007 года
cheburator
589 / / 01.06.2006
Действительно, как-то не подумал...
276
13 августа 2007 года
Rebbit
1.1K / / 01.08.2005
Если есть несколько потоков то функцию getInstance надо както синхронизировать.
3
13 августа 2007 года
Green
4.8K / / 20.01.2000
Цитата: Rebbit
Если есть несколько потоков то функцию getInstance надо както синхронизировать.


Если есть несколько потоков, то придется синхронизировать далеко не только эту функцию. :)

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог