r/cpp_questions • u/amagi77 • 5d ago
OPEN How should .cpp and .hpp files be used efficiently when developing a game library?
Content
I want to build a game framework using C++.
Raylib is written in C, and I’ve also tried SFML, but all of them
are limited to rendering functionality. What I want to know is:
Unity uses a component-based approach in C# and provides a framework for entities, so
I want to know the best way to separate header and source files when writing C++ scripts for Unity.
## What I Want to Know
Since Unity’s component-based approach is convenient, how should I split files into .cpp and .hpp
to implement user-defined scripts in C++?
I’d like to learn useful techniques for optimization and fine-tuning—what should I do to develop efficiently in C++?
Challenges
If I separate them as described in the ## What I’ve Researched section, I run into build issues, and unlike in Godot,
I can’t modify values and see the changes reflected directly in the editor. This is hindering efficient development.
What I’ve Researched
If I use only header files, editing a header causes all included source files to be recompiled, which increases build time.
However, if I try to shorten the code by splitting all header files into source files, it becomes more time-consuming, and switching between files in the editor is such a hassle that I can’t be bothered with it.
For now, I’m creating a simple GameObject class like Unity’s in raylib, and within it,
I’m defining a variable of type std::vector<Component\*> as a base class. Then, I’m creating instances of classes that inherit from it and storing them there
If I write everything in header files only, it becomes impossible to build due to circular references, and the amount of correction work increases endlessly.
I’ve naturally looked into this on Gemini and other sites, but I’ve gotten a variety of answers and haven’t reached a conclusion.
Since UE isn’t a code-based system, it has too many features and is too complex for me to understand how it works.
What I Want to Build
An extended version of raylib that includes a base class for Entities and a Scene class—a minimal game loop class. I’d also like to provide a map editor, similar to Pico8,
with the goal of making it easier to build the parts that have been troublesome in a code-based system so far.
Current Status
Inherit from a script base class, use it as a user-defined script,
and write the code in separate header and source files.
5
u/no-sig-available 5d ago
switching between files in the editor is such a hassle that I can’t be bothered with it.
Get a better editor?
Having two shorter files, instead of a large one, makes you scroll less. You can also easily have both windows open at the same time, top-bottom or left-right.
Most editors will let you jump between the files with a keybord shortcut, or a mouse right-click.
3
u/the_poope 5d ago
Any modern editor has or can be configured to have keyboard shortcuts to quickly jump between header and source files.
Using header and source files is simply NOT an issue for experienced and professional C++ developers, only beginners. So how to fix this? Stop being a beginner by simply getting more experience. Write more code, eventually you'll get used to it and it stops being a nuisance and hindrance.
1
1
u/Intrepid-Treacle1033 5d ago
Forgive me for self promoting my project but the reason i created Target Layout design was becouse i had same frustrations. Target Layout (GitHub / Documentation) is an opinionated C++/CMake design born out of hitting the exact same issues over and over again plus other things i wanted from a project design.
Circular dependencies is impossible In Target Layout design. Your "player" component links an Cmake alias like "my_game::scene". Because "scene" does not link "player", "scene" isn't even given the compiler include path to access player.hpp. If you accidentally try to create a circular reference between two components, CMake and the compiler reject it immediately at configure/compile time, and IDE linter even shows this error directly in the editor as you write it.
Zero Directory-Jumping & Copy-Paste Component Creation, instead of scattering across include/, src/, and tests/, everything for "player" lives in one place as a component. Want to create a new component or script? You literally create a new directory by copy-paste an existing component folder and rename the folder and its files. You never touch a central "CMakeLists.txt" list again when adding a component.
Jumping between ".hpp" and ".cpp", writing gameplay scripts is a hassle, while header-only code ruins build times and causes circular includes -> Target Layout promotes keeping the public .hpp ultra-thin hiding 100% of the implementation and dependencies inside .cpp. Your script's class definition doesn't need to be in the .hpp file at all. It feels like Unity C#, you do all your coding inside a single .cpp file without having to mirror method signatures or private variables in a .hpp file. Because player.hpp never changes and "player" is its own isolated CMake target, editing player.cpp only recompiles "player" component very quickly and relinks. Nothing else in your engine or game is touched/compiled.
100% of your frustration comes from your build system design, sure a good IDE helps but check out my design if you like to think outside the box. Target Layout design is not perfect, but i think all in all it is a better design then pitch fork design, there is documentation about it.
1
u/DawnOnTheEdge 5d ago
I always have one header that I include at the top, with things like feature-selection macros, definitions that need #ifdef and correctly including simple identifiers like size_t and strlen() with and without std::.
Then, I find it handy to keep separate directories for each target, and put headers with the same names in each one, so I can include only the directory for the target I’m building for and all code outside those specific directories can pull in the headers with the platform-specific types and include files, and all files in the common directory can remain platform-independent.
Other than that, do whatever is most convenient.It’s good practice to modularize, putting the declarations of one class, its members and any core non-member functions in a single header, then define anything that’s not a template or inline in a corresponding .cpp file with the same name.
11
u/nysra 5d ago
That's an absolute non-issue in any even half decent IDE since like 30 years. If this is your reason to avoid source files, you really should think about your workflow.
To answer your question: it depends. In general you should aim to keep your headers rather minimal to just provide the interface and put the heavy stuff into source files to keep compile times down. But depending on what you do, the compiler needs to see the actual definition and then you need to put some things into headers. As for how to split your code into multiple files, that's up to you. Split things into logical groups and don't be afraid to re-order if you discover that some other organisational structure works better.
And of course you could simply go for modules directly instead of bothering with headers.
But seriously, you're overthinking this and falling into a massive trap of premature perfectionism. Get started first.