Просто пример, который я использовал в прошлом. Защищенные методы отлично подходят для предоставления функций, специфичных для реализации, и в то же время позволяют базовому классу правильно отслеживать вещи. Рассмотрим базовый класс, который предоставляет переопределяемую функцию инициализации, но также должен иметь состояние, чтобы определить, инициализирован ли он:
class Base
{
private:
bool m_bInitialized;
public:
virtual void Initialize() = 0;
void setInitialized() { m_bInitialized = true; };
bool isInitialized() const { return m_bInitialized; };
}; // eo class Base
Здесь все хорошо. За исключением случаев, когда производный класс не удосуживается вызвать setInitialized()
не в последнюю очередь тот факт, что любой может его вызвать (мы могли бы сделать это защищенным здесь, и еще одна причина использовать защищенные методы!). Я предпочитаю класс, который использует виртуальные защищенные члены:
class Base
{
private:
bool m_bInitialized;
protected:
virtual void InitializeImpl() = 0;
public:
void Initialize()
{
InitializeImpl();
m_bInitialized = true;
}; // eo Initialize
bool isInitialized() const { return m_bInitialized; };
}; // eo class Base
В нашем новом классе вся инициализация по-прежнему делегируется производному классу. При условии, что было сгенерировано исключение, мы поддерживаем контракт «этот класс инициализирован», который, как говорит наш метод, произойдет.