Закрытые конструкторы полезны, когда существуют требования к конструкции, которые не могут быть гарантированы только конструктором. Например, если метод инициализации должен быть вызван сразу после конструктора, или если объект должен зарегистрировать себя в каком-либо объекте контейнера / менеджера, это должно быть сделано вне конструктора. Ограничивая доступ к конструктору и предоставляя только фабричный метод, вы можете гарантировать, что любой экземпляр, который получает пользователь, будет выполнять все свои гарантии. Это также обычно используется для реализации Singleton, что на самом деле является еще одной гарантией, которую дает класс (что будет только один экземпляр).
Причина создания защищенного конструктора, а не частного, та же, что и для создания любого другого метода или поля, защищенного вместо частного: так, чтобы он мог наследоваться дочерними элементами. Возможно, вам нужен открытый, не виртуальный фабричный метод в базовом классе, который возвращает ссылки на экземпляры производных классов; производные классы, очевидно, хотят получить доступ к родительским конструкторам, но вы все равно не хотите создавать их вне вашей фабрики.