Существует несколько подходов, и правильный подход действительно зависит от того, что делает класс.
Довольно часто имеет смысл иметь публичный API, который позволяет читать информацию, и в этом случае операторам потоковой передачи не требуется доступ к частным лицам.
Вероятно, самый популярный подход - объявить потоковые функции друзьями класса.
Мой фаворит - предоставление публичной функции шаблона стиля Boost.Serialization, которую можно использовать для потоковой передачи в любом случае, а также для других целей.