Проблема наследования

Если существует необходимость наследовать от класса Singleton, то следует придерживаться определенных правил.

Во-первых, класс-наследник должен переопределить метод Instance(), так, чтобы создавать экземпляр производного класса. Если не предполагается, что указатель будет использоваться полиморфно, то можно объявить возвращаемый тип метода Instance() как указатель на класс-наследник, в противном случае, метод Instance() должен возвращать указатель на базовый класс (Singleton).

Во-вторых, в базовом классе деструктор должен быть объявлен как виртуальный: в определенный момент клиент вызывает метод FreeInst для указателя на базовый класс. Поскольку метод FreeInst сводится к оператору delete this, то в случае, если деструктор не виртуальный, будет вызван деструктор базового класса, но не будет вызван деструктор класса-потомка. Чтобы избежать такой ситуации, следует явно объявить деструктор базового класса виртуальным.

В-третьих, конструктор класса-потомка также должен быть объявлен в защищенной секции, чтобы избежать возможности создания объекта класса напрямую, минуя метод Instance().

Листинг 7

class Singleton {

protected:

 static Singleton* _self;

 static int _refcount;

 Singleton(){}

 virtual ~Singleton() {printf ('~Singleton ');}

public:

 static Singleton* Instance();

 void FreeInst();

};

class SinglImpl: public Singleton {

protected:

 SinglImpl(){}

//объявление виртуальным в базовом классе автоматически

 //дает виртуальность в производном.

 ~SinglImpl() {printf ('~SinglImpl ');}

public:

 static Singleton* Instance() {

  if(!_self) _self = new SinglImpl();

  _refcount++;

  return _self;

 }

};

void main() {

 Singleton *p = SinglImpl::Instance();

 …

 …

 …

 p->FreeInst();

}

Результат работы:

~SinglImpl

~Singleton

Иногда может возникнуть ситуация, при которой клиент должен полиморфно работать с объектами, имеющими общий базовый класс, но некоторые из них реализуют паттерн Singleton, а некоторые нет. Проблема возникает в момент освобождения объектов, так как у простых классов нет механизма отслеживания ссылок, а у классов, реализующих Singleton, он есть. При вызове метода FreeInst() через указатель на базовый класс будет вызываться FreeInst() базового класса, не имеющего понятия о подсчете ссылок. Это приведет и к безусловному удалению объектов “Singleton” из памяти. Для предотвращения такого поведения следует объявить виртуальным метод FreeInst() в базовом классе и реализовать специфическое поведение метода для классов Singleton. Реализация FreeInst() в базовом классе предоставляет механизм удаления объектов, не являющихся Singleton’ами.

Листинг 8

class base {

protected:

 virtual ~base(){} //гарантируем удаление только через FreeInst()

public:

 virtual void Do1()=0;

 virtual void FreeInst(){delete this;}

};

class Simple: public base {

protected:

 ~Simple () {printf('Simple::~Simple ');}

public:

 void Do1(){printf('Simple::Do1 ');}

};

class Singleton: public base {

 static Singleton* _self;

 static int _refcount;

protected:

 Singleton(){}

 ~Singleton () {printf('Singleton::~Singleton ');}

public:

 static Singleton* Instance() {

  if(!_self) _self = new Singleton ();

  _refcount++;

  return _self;

 }

 void FreeInst() {_refcount--; if(!_refcount) {delete this; _self=NULL;}}

void Do1(){printf('Singleton::Do1 ');}

};

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату
×