Ценой предлагаемого вами способа сокрытия реализации является то, что пользователь вашего класса не сможет самостоятельно объявлять объекты вашего класса, расположенные целиком в локальной или статической памяти. Раз компилятору не видно полное определение класса, то ему не известен и полный размер этого класса и, соответственно, создавать объекты такого класса в коде пользователя компилятор не может. Поэтому создавать объекты придется где-то в недрах кода, знакомого с полным устройством класса, и возвращать их наверх пользователю по указателю. Это означет, что обязательно придется использовать какую-то форму динамической памяти для хранения объекта или хотя бы "скрытых" его частей.
Например, в самом экстремальном варианте, содержимое класса не видно пользователю вообще
class CFileHandle;
В такой ситуации пользователь не может определять объекты такого класса самостоятельно. Он может только вызывать какую-то функцию данной библиотеки, которая будет внутри динамически создавать объекты данного класса (либо через new, либо еще как) и возвращать пользователю указатель на них
CFileHandle *create_file(/* whatever */);
Разнообразные "промежуточные" варианты сокрытия реализации, как популярная PIMPL idiom, описанная в ответе @VladD, точно таким же образом вынуждены пользоваться динамическим выделением памяти для сокрытой части объекта.
Требование безусловного использования динамической памяти испокон веков считалось неприемлемым языках С и С++, ориентированных на эффективность генерируемого кода (в языке С эта же проблема предстает в точно такой же форме). Также факт сокрытия реализации части класса не позволяет обрабатывать соответствующие скрытые части объектов при помощи inline-функций.
Поэтому сам язык С++ на его базовом уровне настроен именно на определение всего класса, со всеми потрохами, в заголовочном файле, тем самым давая пользователю возможность самостоятельно определять объекты такого класса и работать с ними максимально эффективно (без ненужных накладных расходов). А уж если вас не устраивает такая полная видимость определения класса и вы готовы немножко пожертвовать производительностью, то вам предлагается пользоваться рукописными идиомами типа PIMPL idiom.
DogImplвы можете определять как угодно. Я бы оставил inline, но если вам больше нравится вне класса, то можно и так. В любом случае имплементациюDogImplникто не видит, кроме вас :) – VladD Jul 07 '15 at 12:12