Как разнести класс по файлам?
Принцип прост. В .h можно ставить только то, что не производит кода. Как только в проекте появится второй CPP и задействует этот хедер, код будет произведён дважды, и компоновщик (cl/ld/ilink) будет ругаться, что переменная или функция в двух экземплярах. Что именно не производит кода…
• Определения макросов. Они в принципе кода не производят.
• Объявление любого типа. Оно лишь говорит об устройстве этого самого типа; код же производят те, кто этим типом пользуются.
• Шаблоны. Код производит не сам шаблон, а факт расшаблонивания. Разумеется, шаблон может расшаблониться в двух единицах компиляции, но с этим автоматически бороться научились.
• inline—  код производит не сам inline, а факт включения. inline бывает как явный ключевым словом, так и неявный — в теле класса.
• Прототипы и extern — они говорят: код есть, но где-то не здесь.
• Constexpr C++11. Они подставляют значение.
• Некоторые const в зависимости от компилятора. Например, на Borland const double производит код, а const int — нет.
Производят код и в хедерах запрещены.
• Переменная без extern, даже const.
• Функция, которая не inline.
• Полностью специализированный шаблон, в котором не осталось шаблонных параметров (template<>).
Не производят кода, но и лучше закинуть в CPP.
• Некоторые скрытые (private) inline и шаблоны, если они не используются из хедера.
Насколько дурным тоном будет реализовать весь такой класс в одном файле (в .h например)?
Их специально сделали отдельными, потому что они не компилируются, а только вставляются напрямую через include. Некоторые расчитаны на единственную вставку (тогда делаются ворота из ifndef), а некоторые - на множественную вставку (тогда и ворота из ifndef не нужны). И вот когда они вставлены, тогда они и компилируются уже в контексте того места, куда они вставлены.
Назначение файлов .h - сделать видимыми имена (объявить имена).