6.04 Class Invariant Preservation, Setter Input Validation & Small Object Design
Executive Summary: Designing classes that enforce strict data validation rules through encapsulation. We analyze invariant preservation in setter methods and modern techniques for managing identity and credentials in embedded IoT devices.
💻 1. Annotated Source Code
#include <iostream> #include "LibraryCard.h" using namespace std; void printLibraryCardDetails(const LibraryCard& card); int main() { LibraryCard aliceCard("Alice Johnson"); LibraryCard bobCard("Bob Smith"); aliceCard.checkoutBook(); aliceCard.checkoutBook(); bobCard.checkoutBook(); printLibraryCardDetails(aliceCard); printLibraryCardDetails(bobCard); cout << "Alice returns a book... " << endl; aliceCard.returnBook(); printLibraryCardDetails(aliceCard); bobCard.returnBook(); bobCard.returnBook(); //should trigger a warning! return 0; } void printLibraryCardDetails(const LibraryCard& card) { cout << card.getCardholderName() << " has " << card.getBooksCheckedOut() << " books checked out." << endl; }
#ifndef LIBRARY_CARD_H #define LIBRARY_CARD_H #include <string> using namespace std; class LibraryCard { public: LibraryCard(string cardholderName); void checkoutBook(); void returnBook(); string getCardholderName() const; int getBooksCheckedOut() const; private: string cardholderName; int booksCheckedOut; }; #endif
#include "LibraryCard.h" #include <iostream> using namespace std; LibraryCard::LibraryCard(string cardholderName) { this->cardholderName = cardholderName; booksCheckedOut = 0; } void LibraryCard::checkoutBook() { booksCheckedOut++; } void LibraryCard::returnBook() { if (booksCheckedOut > 0) { booksCheckedOut--; } else { cout << "No books to return!" << endl; } } string LibraryCard::getCardholderName() const { return cardholderName; } int LibraryCard::getBooksCheckedOut() const { return booksCheckedOut; }
📐 2. Architecture & UML Class Model
<<class>>
LibraryCard
Domain Entity
Attributes / Data Members
-cardHolderName : std::string
-cardNumber : int32_t
-booksCheckedOut : int32_t = 0
Operations / Methods
+LibraryCard(holder: string, cardNum: int)
+checkOutBook() : bool
+returnBook() : bool
+getCardHolderName() : std::string const
+getCardNumber() : int32_t const
+getBooksCheckedOut() : int32_t const
📚 3. Core C++ Concepts Deep-Dive
1. Setter Validation
Setters act as gatekeepers, verifying input ranges before mutating private member variables to guarantee the object never enters an invalid state.
⚡ 4. Embedded Systems & Hardware Reality
1. Secure Device Identity Storage
In IoT edge devices, credentials (e.g. device serial numbers, cryptographic MAC addresses) are validated during provisioning and stored in secure write-once Flash sectors.
💡 5. Production-Ready Embedded Refactoring
Type-safe validated identity class:
💡 Production-Ready Refactor
#include <cstdint> #include <string_view> class DeviceAuthToken { private: uint32_t device_uid_{0}; uint16_t security_pin_{0}; bool is_valid_{false}; public: constexpr bool provision(uint32_t uid, uint16_t pin) noexcept { if (uid == 0 || pin < 1000 || pin > 9999) { return false; // Invariant violation: PIN must be 4 digits } device_uid_ = uid; security_pin_ = pin; is_valid_ = true; return true; } constexpr bool is_authenticated() const noexcept { return is_valid_; } };
📝 Knowledge Verification Quiz
Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.
Q1. What is an 'object invariant' in class design?
Detailed Explanation:
An invariant is a fundamental truth about an object's state (e.g., speed $\ge 0$, pointer $\ne$ null) that constructors establish and methods maintain.
Q2. Why should member variables generally be kept private with public getters/setters instead of being made public?
Detailed Explanation:
Private fields force all modifications to pass through validator methods, preventing external corruption of object state.
Q3. What should a setter function do if passed an invalid argument in an embedded system compiled with -fno-exceptions?
Detailed Explanation:
When exceptions are disabled, setters should return a boolean or status code indicating rejection, preserving the existing valid state.
Q4. What is the benefit of making accessor (getter) methods inline?
Detailed Explanation:
Inline getters eliminate function call branches (
BL/BX LR) in assembly, executing as fast as raw field access while preserving encapsulation.