Create a class SensorConfig that represents configuration data for a digital sensor in an embedded system.
Each sensor must be initialized with valid configuration data at startup, specifically a sensor ID and a calibration offset. The system must not allow uninitialized sensor objects.
The class must store the latest calibrated sensor value and update it whenever new raw data is received.
Class Requirements
The class SensorConfig must contain the following private data members:
int id — unique sensor identifierint offset — calibration offset applied to raw readingsint lastValue — last calibrated value (must be initialized to 0)Constructor Requirements
The class must define only one constructor:
SensorConfig(int sensorId, int calibrationOffset)
The constructor must:
sensorId to idcalibrationOffset to offsetlastValue to 0❗ A default constructor must not be used.
Public Member Functions
void update(int raw)lastValue = raw + offset
int read()lastValueMain Function Behavior
In main():
id and offsetSensorConfig object using the parameterized constructorr1 and r2update(r1) followed by update(r2)read()Input Format
id offset
r1 r2
Output Format
<final_calibrated_value>
Example Input
10 3
20 25
Example Output
28
Explanation
3update(20) → lastValue = 23update(25) → lastValue = 2828
Constraints
A Constructor is a special member function that runs automatically when an object is created. Its purpose is to guarantee that the object starts in a valid state (e.g., pointers assigned, hardware initialized, invariants checked) before any other code uses it.
It has no return type and shares the same name as the class.
1. Basic & Parameterized Constructors
The most common forms used to initialize variables.
class GPIO {
int pin;
public:
// 1. Default Constructor (No args)
GPIO() { pin = 0; }
// 2. Parameterized Constructor (With args)
GPIO(int p) { pin = p; }
};
GPIO led; // Calls GPIO()
GPIO motor(9); // Calls GPIO(int)2. Member Initializer Lists (Crucial for Efficiency)
Initializes variables before the constructor body runs. This is mandatory for const members and References, and avoids "double-writing" variables.
class Sensor {
const int id;
int& bus_ref;
public:
// Syntax: : member(value), member(value)
Sensor(int i, int& bus) : id(i), bus_ref(bus) {
// Body is empty; work is already done.
}
};3. Advanced Variants (explicit, Copy, delete)
These control how objects are created or copied, preventing dangerous bugs.
explicit: Prevents accidental implicit conversions (e.g., passing int where a Driver object is expected).= delete: Disables a constructor (used for Singletons or unique hardware drivers).class Driver {
int* buffer;
public:
// PREVENT implicit conversion from int to Driver
explicit Driver(int size) { buffer = new int[size]; }
// CUSTOM Copy Constructor (Deep Copy)
Driver(const Driver& other) {
buffer = new int[10];
memcpy(buffer, other.buffer, 10 * sizeof(int));
}
// DISABLE Copying entirely (Common for hardware drivers)
// Driver(const Driver&) = delete;
};| Feature | Assignment (Inside Body) | Initializer List (: x(10)) |
|---|---|---|
| Mechanism | Variable created (default), then overwritten. | Variable created with value. |
| Performance | Slower (Two steps). | Faster (One step). |
| Constraints | Cannot init const or Reference. | Required for const/Reference. |
1. Impossible-to-Forget Initialization
In C, forgetting UART_Init() crashes the system.
In C++, constructors force you to provide configuration (e.g., Baud Rate) at creation time. The object never exists in an uninitialized state.
2. RAII (Resource Acquisition Is Initialization)
The "Scope Lock" pattern: A constructor acquires a resource (disables interrupts, takes a mutex), and the Destructor releases it.
{
InterruptLock lock; // Constructor: __disable_irq();
// Critical Section
} // Destructor: __enable_irq(); automatic at end of scope.
3. Unique Hardware Access
Using = delete on copy constructors ensures you don't have two software objects trying to control the same physical UART peripheral, preventing race conditions.
| Pitfall | Details |
|---|---|
| ❌ Heavy Work | Avoid complex hardware delays or checks in constructors for Global/Static objects. They run before main(), which can make the system appear to hang at boot. |
| ❌ Initializer Order | Members are initialized in the order they are declared in the class, NOT the order in the list.
|
| ❌ Implicit Conversion | Without explicit, void func(Driver d) can be called as func(100), silently creating a 100-byte driver. This is confusing and dangerous. |
| ✅ Default Constructor | If you define any constructor, the compiler removes the default (empty) one. You must explicitly add GPIO() = default; if you still need it. |