100 lines
3.3 KiB
Text
100 lines
3.3 KiB
Text
%% title = "C++ without Classes"
|
|
|
|
% id = "01JN6EFWCPWY65AQ27BGFDT2DV"
|
|
- one thing I often see in people's code in C++ is putting _everything_ into a class.
|
|
|
|
% id = "01JN6EFWCPNBZA3P7NPTPJYFN5"
|
|
- there's nothing wrong with putting code that actually, y'know, _uses the class_, in the class, but it irks me when I see things like helper functions and other implementation details being in the class.
|
|
|
|
% id = "01JN6EFWCPHYJNV6WDF1WJ3RSF"
|
|
- private functions have the unfortunate consequence of being part of the public header, even though they are implementation details!
|
|
this means if you edit them, you have to edit both the .cpp implementation file, as well as the .h header.
|
|
|
|
% id = "01JN6EFWCPHBEBPZXC34H65BMS"
|
|
- which is precisely what C++ without Classes is about.
|
|
since updating method signatures is a pain in the ass... just don't do it!
|
|
|
|
% id = "01JN6EFWCP8996EGW6P1AX203J"
|
|
- declare all your fields public, and let `static` functions within your `.cpp` file work the magic.
|
|
|
|
% id = "01JN6EFWCPPFW6N974T6GG0YZN"
|
|
- and here you might say: "but I don't _want_ to have these fields public! it breaks encapsulation!"
|
|
to which I respond: so make your data structure private!
|
|
|
|
% id = "01JN6EFWCPEJ60RTS66314K7NN"
|
|
- example of C++:
|
|
|
|
#### world.h
|
|
|
|
```cpp
|
|
struct World
|
|
{
|
|
// ... fields ...
|
|
|
|
void update(const Update_Context& context);
|
|
|
|
private:
|
|
void update_aims(const Update_Context& context);
|
|
};
|
|
```
|
|
|
|
#### world.cpp
|
|
|
|
```cpp
|
|
void World::update(const Update_Context& context)
|
|
{
|
|
update_aims(context);
|
|
}
|
|
|
|
void World::update_aims(const Update_Context& context)
|
|
{
|
|
// ...
|
|
}
|
|
```
|
|
|
|
% id = "01JN6EFWCP00TB3PGNVNP1T7S5"
|
|
- example of C++ without Classes:
|
|
|
|
#### world.h
|
|
|
|
```cpp
|
|
struct World
|
|
{
|
|
// ... fields ...
|
|
};
|
|
|
|
void update(World& world, const Update_Context& context);
|
|
```
|
|
|
|
#### world.cpp
|
|
|
|
```cpp
|
|
static void update_aims(World& world, const Update_Context& context)
|
|
{
|
|
// ...
|
|
}
|
|
|
|
void update(World& world, const Update_Context& context)
|
|
{
|
|
update_aims(world, context);
|
|
// ...
|
|
}
|
|
```
|
|
|
|
% id = "01JN6EFWCPER7ZSEA8NY0Z0JX2"
|
|
- suddenly, the publicly available part of `world.h` has gotten smaller---there's one method less.
|
|
the implementation detail `update_aims` does not leak into the header; we don't have to update the signature in two places if we ever want to change it, and it does not cause a recompilation if we edit it.
|
|
|
|
% id = "01JN6EFWCP0XMH10NE6THK58EV"
|
|
- I took the `update` method out of the struct to signal the lack of coupling.
|
|
_anyone_ can do what `update` does; it doesn't matter.
|
|
every function is at the same level as the struct itself.
|
|
|
|
% id = "01JN6EFWCP3JV68Z1FR64V16JA"
|
|
- in my own code, outside this contrived example, I also put functions related to a data structure in a namespace---in this case, `update(World&, const Update_Context&)` would be `world::update(World&, const Update_Context&)`.
|
|
this is purely a stylistic preference---I like the extra explicitness over leaning on overloads.
|
|
|
|
% id = "01JN6EFWCPNSQH38ED9ASC0CMX"
|
|
- I've been enjoying this style a lot.
|
|
it takes edge cases like `this` out of the language, and results in simpler, more easily editable code.
|
|
so I wholeheartedly recommend giving it a try!
|