Каждому классу присвоить id (целое число), и написать для этого класса функции записи в бинарный поток и чтения из него. Записывать непосредственно значения полей.
Если потребуется прямой доступ к объектам, то при создании файла отвести в начале место для ссылок на положение каждого элемента массива в файле, потом, по мере создания файла накапливать эти ссылки. В конце записать. Если прямого доступа не нужно - писать и потом читать все объекты подряд.
Если структура классов будет меняться, и иногда потребуется читать старые файлы, надо предусмотреть номер версии, чтобы десериализатор класса мог его учитывать. Читать новый файл старой программой при этом не получится.
Если есть информация о диапазонах значений полей, можно записывать меньше байтов, чем размер типа (например, для целых - два или три байта). Для массивов можно предусмотреть упаковки какими-нибудь разностными схемами.