Решение довольно плохое, его можно улучшить с помощью CRTP (это делает Adobe), но оно не будет полным решением. Проблема с вашим кодом заключается в том, что другой программист, который не хочет нарушать ваш контракт (она хороший человек), но не знает, что она не должна быть производной от вашего класса, может захотеть заблокировать других от получения из своего собственного класса:
class YourSealedClass : private virtual final {};
class HerSealedClass : public YourSealedClass, private virtual final {
};
Обратите внимание, что нет даже злого умысла, и договор расторгнут. Улучшение с CRTP будет:
template <typename T>
class seal
{
protected:
seal(){}
~seal(){}
};
class YourSealedClass : private virtual seal<YourSealedClass> {};
Это поймает предыдущую ошибку, так как ее код будет:
class HerSealedClass : public YourSealedClass, private virtual seal<HerSealedClass> {};
И поскольку она не наследует от seal<YourSealedClass>
, компилятор ее догонит.
Проблема этого подхода заключается в том, что он не блокирует некоторых упрямых (или злых) программистов от написания:
class MalignClass : public YourSealedClass, private virtual seal<YourSealedClass> {};
Стать ребенком в классе запечатывания и получить доступ к своему классу.
В C ++ 0x я верю (придется перепроверить его), что они снимают ограничение на то, что шаблон не может подружиться с аргументом шаблона, и это будет хорошим шагом в универсальном типобезопасном решении для герметика класса:
template <typename T>
class seal {
friend class T; // illegal in C++03
seal() {};
~seal() {};
};
class MySealedClass : private virtual seal<MySealedClass>
{};
Преимущество этого подхода (в настоящее время недоступного) состоит в том, что, поскольку конструктор и деструкторы являются частными, только друзья могут создавать экземпляры типа. Поскольку вы используете CRTP для наследования от конкретного экземпляра, передавая свой собственный тип в качестве аргумента, вы говорите компилятору, что только вы могут на самом деле создать экземпляр вашей базы, и все части встанут на свои места.