Класс, содержащий защищенный раздел, означает, что этот класс позволяет производным классам манипулировать своим базовым классом любым способом, который они выбирают (насколько позволяет защищенный интерфейс).
Объекты класса D могут манипулировать своими собственными Aчасть.Делая, скажем, они, вероятно, хотят сохранить некоторые инварианты.
Предположим, есть (или будет в будущем!) Другой класс E, также унаследованный от A. Объекты класса E также могут манипулировать своей собственной частью A, иони могут применять разные инварианты.
Теперь, если объекту класса D было разрешено манипулировать частью A любого объекта, он не может обеспечить инварианты.Объект AD может что-то делать с частью A объекта E, что нарушает этот объект E.Вот почему это недопустимо.
Но если вы действительно этого хотите, возможно, способ вызвать A :: f, не раскрывая его всем, был бы через функцию друга.
class A;
namespace detail
{
void call_f(A*);
}
class A
{
friend void detail::call_f(A*);
private:
virtual void f() = 0;
};
namespace detail
{
void call_f(A* a) { a->f(); }
}
class D: public A
{
public:
void g() { detail::call_f(mAPtr); }
private:
void f() {}
A* mAPtr;
};
Это полагается на то, что пользователи достаточно дисциплинированы, чтобы держаться подальше от пространств имен, чье имя ясно указывает на то, что оно содержит детали реализации.