Project 6.04 Section 6 ⚡ Embedded Relevance: Core Invariants Validation OOP Encapsulation State Management

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

📐 LibraryCard Entity & Transactional Method Model
+ Public - Private # Protected
<<class>> LibraryCard Domain Entity
-cardHolderName : std::string
-cardNumber : int32_t
-booksCheckedOut : int32_t = 0
+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?
A A condition or rule that must always hold true for an object to remain in a valid, functional state throughout its lifetime
B A variable marked const that cannot be changed
C A function that runs in constant time
D A class with no private members
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?
A To prevent external code from setting members to invalid/corrupt values, preserving class invariants
B To make the binary file smaller
C To enable multithreading automatically
D To force variables into Flash memory
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?
A Reject the mutation and return a boolean false or error status code without changing state
B Execute a busy loop forever
C Overwrite the variable with zero silently
D Restart the CPU
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?
A The compiler replaces the function call with direct memory access in assembly, eliminating function call overhead completely
B It converts the getter into a macro
C It allocates getters on the heap
D It allows getters to mutate private members
Detailed Explanation: Inline getters eliminate function call branches (BL/BX LR) in assembly, executing as fast as raw field access while preserving encapsulation.