Project 6.02 Section 6 ⚡ Embedded Relevance: Core Member Initializer List constexpr OOP Const Correctness Invariants

6.02 Member Initializer Lists, Invariant Verification & constexpr Geometry Math

Executive Summary: Building geometric classes with constructors and member initializer lists. We analyze why member initializer lists are strictly more efficient than assignment inside the constructor body, and how to make geometry classes 100% constexpr for compile-time layout calculations.

💻 1. Annotated Source Code

#include <iostream>
#include "Rectangle.h"
using namespace std;

int main() {

	Rectangle r1;
	Rectangle r2(5.0, 2.0);

	cout << "r1 area is " << r1.area() << endl;
	cout << "r2 area is " << r2.area() << endl;
	cout << "r1 perimeter is " << r1.perimeter() << endl;
	cout << "r2 perimeter is " << r2.perimeter() << endl;

	r1.setLength(22);
	r1.setWidth(12);

	cout << "r1 length is now " << r1.getLength() << endl;
	cout << "r1 width is now " << r1.getWidth() << endl;

	cout << "r1 area is NOW " << r1.area() << endl;

	return 0;
}
#ifndef RECTANGLE_H
#define RECTANGLE_H

class Rectangle {
	public:
		Rectangle();
		Rectangle(double length, double width);
		double getLength() const;
		double getWidth() const;
		void setLength(double length);
		void setWidth(double width);
		double area() const;
		double perimeter() const;

	private:
		double length;
		double width;
};

#endif
#include "Rectangle.h"

Rectangle::Rectangle() {
	this->length = 1.0;
	this->width = 1.0;
}// no-arg ctor 

Rectangle::Rectangle(double length, double width) {
	this->length = length;
	this->width = width;
}// end parameterized ctor

double Rectangle::getLength() const {
	return length;
}

double Rectangle::getWidth() const {
	return width;
}

void Rectangle::setLength(double length) {
	this->length = length;
}

void Rectangle::setWidth(double width) {
	this->width = width;
}

double Rectangle::area() const {
	return length * width;
}

double Rectangle::perimeter() const {
	return 2 * length + 2 * width;
	//return 2 * (length + width);
}

📐 2. Architecture & UML Class Model

📐 Rectangle Class Invariant Enforcement & Area Model
+ Public - Private # Protected
<<class>> Rectangle Geometric Entity
-length : double
-width : double
+Rectangle()
+Rectangle(length: double, width: double)
+getLength() : double const
+getWidth() : double const
+setLength(length: double) : void
+setWidth(width: double) : void
+area() : double const
+perimeter() : double const

📚 3. Core C++ Concepts Deep-Dive

1. Member Initializer Lists vs Body Assignment

In a constructor, member initializer lists (Rectangle::Rectangle(double l, double w) : length(l), width(w) {}) initialize members directly when memory is allocated, avoiding double-initialization overhead.

📐 Rectangle Class UML Architecture

<<value-object>> Rectangle
- length : double
- width : double
+ Rectangle()
+ Rectangle(l: double, w: double)
+ getLength() : double const
+ getWidth() : double const
+ area() : double const
+ perimeter() : double const

2. const Member Functions

Methods that do not modify class state (getLength() const, area() const) must be marked const, allowing them to be called on const objects in Flash ROM.

⚡ 4. Embedded Systems & Hardware Reality

1. constexpr Compile-Time Objects

Declaring geometry constructors and methods constexpr allows UI display coordinates, bounding boxes, and clip rects to be calculated during compilation, producing zero runtime CPU cycle overhead.

💡 5. Production-Ready Embedded Refactoring

100% constexpr UI bounding box class:

💡 Production-Ready Refactor
#include <cstdint>

class BoundingBox {
private:
    int16_t x_{0};
    int16_t y_{0};
    uint16_t width_{0};
    uint16_t height_{0};

public:
    constexpr BoundingBox(int16_t x, int16_t y, uint16_t w, uint16_t h) noexcept
        : x_(x), y_(y), width_(w), height_(h) {}

    constexpr uint32_t area() const noexcept { return static_cast<uint32_t>(width_) * height_; }
    constexpr bool contains(int16_t px, int16_t py) const noexcept {
        return (px >= x_ && px < (x_ + width_) && py >= y_ && py < (y_ + height_));
    }
};

// Computed at compile-time and placed in Flash .rodata
constexpr BoundingBox STATUS_BAR_RECT{0, 0, 320, 24};
constexpr uint32_t STATUS_BAR_AREA = STATUS_BAR_RECT.area(); // 7680

📝 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. Why is using a member initializer list (Class() : member(val) {}) preferred over body assignment (Class() { member = val; })?
A It initializes the member directly during object construction, avoiding default-initialization followed by assignment
B It automatically allocates memory on the heap
C It makes the class abstract
D It disables constructor overloading
Detailed Explanation: Member initializer lists construct fields in-place. Body assignments default-construct the member first and then invoke the assignment operator, wasting cycles for complex objects.
Q2. In what order are member variables initialized in a C++ class?
A In the exact order they are declared in the class definition, regardless of their order in the constructor initializer list
B In the order listed in the constructor initializer list
C Alphabetical order
D Random order determined by the compiler
Detailed Explanation: C++ strictly specifies that members are initialized in the order of their declaration inside the class body. Compilers with -Wreorder warn if the initializer list is in a different order.
Q3. What does marking a member function 'const' guarantee?
A The function promises not to modify any non-mutable member variables of the object and can be called on const instances
B The function executes in constant O(1) time
C The function returns a constant pointer
D The function cannot accept parameters
Detailed Explanation: const member functions guarantee that this is a pointer to const, permitting calls on immutable objects stored in Flash memory.
Q4. Can a constexpr class constructor execute at runtime if passed non-constant arguments?
A Yes, constexpr constructors can run either at compile-time or runtime depending on whether their inputs are constant expressions
B No, constexpr functions only work at compile time
C No, it causes a compilation failure
D Yes, but only in debug mode
Detailed Explanation: constexpr functions and constructors are versatile: when given compile-time constants they evaluate during compilation; when given runtime variables they execute normally at runtime.