C++ Classes and Encapsulation for Embedded Code
Group related state and operations into a small class with a predictable interface.
A class is a small instrument with controls on its front panel. Users operate those controls without reaching into the wiring.
A class combines data and the functions that operate on it. Encapsulation means the public interface defines valid operations while private data prevents accidental changes from unrelated code. A counter class can expose increment and value without allowing every caller to overwrite its internal state arbitrarily.
Constructors initialize objects. An invariant is a condition that every valid object maintains, such as a count never exceeding its limit. Each operation should preserve that rule. This reduces duplicated checks at call sites and makes behavior easier to test with a few input sequences.
Using a class does not automatically require dynamic allocation, inheritance or virtual functions. A small object can be created in automatic or static storage. Embedded projects often benefit from simple value types and explicit dependencies. Inspect generated code and memory use when performance constraints matter rather than assuming every abstraction is either free or expensive.
Do not initialize hardware too early merely because a global constructor can run before main. Platform startup order may not have made the clocks or drivers ready. Separate data initialization from an explicit begin or init call when the platform requires it. The example below is deliberately hardware-independent, so it can be compiled and checked on a desktop.
Group related state and operations into a small class with a predictable interface.
Core ideas
- Keep related state and behavior together.
- Initialize every member and preserve a clear invariant.
- A class does not imply heap allocation.
Counter invariant: 0 ≤ value ≤ limitIncrement at limit leaves the value unchangedWork through a practical example
1Construct a bounded counter with limit two.
2Call increment three times.
3The first two calls increase the value; the third leaves it at two.
4Print the result. Callers never need direct access to the private count.
Introducing a large inheritance hierarchy before a simple class and clear interface solve the problem.
Code example
C++17 — standalone program; expected output: 2
#include <cstdio>
class Counter {
unsigned count_ = 0;
unsigned limit_;
public:
explicit Counter(unsigned limit) : limit_(limit) {}
void increment() { if (count_ < limit_) ++count_; }
unsigned value() const { return count_; }
};
int main() {
Counter counter{2};
counter.increment();
counter.increment();
counter.increment();
std::printf("%u\n", counter.value());
}Read and run this example in the stated environment. Code is displayed here; it does not execute in your browser.