понедельник, 24 августа 2009 г.

Блокирование наследования в С++

Представим на минуту что мы пишем инструментальную библиотеку, в которой есть менеджер сессий входа в систему, причем реализовать его требуется как синглтон и кроме того заблокировать возможность наследования от этого класса, поскольку пр наследовании и переопределении методов менеджера программа может работать неустойчиво или попросту падать.
Итак перед нами интересный вопрос на эрудицию: как заблокировать наследование от класса в С++? Напомню, что в C# и Java такая возможность существует. Как же ее реализовать в С++?
Многие скорее всего кинуться делать макросы или просто попытаются пихнуть в базовый класс какую-нибудь статическую переменную для проверки пронаследован класс или нет. Однако это не поможет. При та5ком подходе мы упускаем одну очень важную деталь: все эти проверки будут происходить во времяы выполнения и кроме того всегда возвращать неверные значения, поскольку по правилам C++ конструктор базового класса ВСЕГДА вызывается первым.
Так как же быть?
Ответ настолько же прост насколько и сложен: необходимо перенести деструктор класса в private часть класса. Читатель может возразить: при чем же здесь деструктор?

Предлагаю взглянуть на следующий фрагмент кода:


class SessionManager
{
public:
bool login(std::string& name, std::string& password);
void logout();
static bool create();
static bool destroy();
static SessionManager* instance();
private:
static SessionManager* m_self;
// блокируем констрктор
SessionManager();
// блокируем деструктор!!!
~SessionManager();
// блокируем оператор присваивания
SessionManager& operator = (const SessionManager&);
};

class SessionManagerDerived : public SessionManager
{
............
............
static bool create() {
// ошибка времени компиляции:
// невозможно создать объект класса с закрытым деструктором!
if (!m_self) return new SessionManagerDerived();
return m_self;
}
};



Вот и вся фишка: компилятор не позволит создать класс с закрытым деструктором, поскольку не знает как его удалять! Замечу что для класса SessionManager компилятор имеет эти данные хоть они и в private части.

Комментариев нет: