Private — на что? Ведь тот, кто пойдёт этот интерфейс реализовать, их не увидит.
С protected штука более сложная. Дело в том, что в классическом интерфейсе ноль кода и данных, и эти protected должен вызывать — кто — разумеется, потомки. Преждевременно увековечивать внутреннюю архитектуру — зачем?
Встречается ещё такая штука, как «прокачанный интерфейс» — не знаю, как он правильно называется по ООП. Там есть две новых вещи: 1) утилиты — невиртуальные функции, которые представляют собой стандартный сценарий пользования интерфейсом; 2) штатные реализации — некоторым виртуальным функциям придумывают реализацию, которая как-то работает и пользуется другими виртуальными, но потомок, если захочет, может написать более эффективную версию.
Вот например, утилита.
// write Intel word
void st::Stream::writeIW(uint16_t w)
{
write(&w, sizeof(uint16_t));
}
Утилита
не часть интерфейса, и лучший синтаксис для утилит — методы-расширители C#. На худой конец подойдёт простая функция типа
Streams.writeIW(stream, 10);
.
Вот, например, штатная реализация.
// Возвращает остаток потока
// cu_minus = clipped unsigned minus
virtual Pos remainder() { return cu_minus<Pos>(size(),pos()); }
Если в языке нет штатных реализаций, строят класс, где эти функции чем-то реализованы — не всегда, но часто можно унаследоваться от этого класса.
Раз утилита пользуется обычными общедоступными функциями, нет никакого смысла её кидать в protected (теоретически private/protected могут быть некоторые части сложных утилит). Штатные реализации — тем более, это такая же часть интерфейса, как абстрактные size() и pos().