85. Sensor Calibration Class

Design and implement a simple Embedded C++ class that models a calibrated sensor.

You must define a class named Sensor that stores raw sensor readings and applies a calibration offset before reporting the final value.

Requirements

  1. Class Definition
    • Define a class Sensor.
  2. Private Data Members
    • int rawValue — stores the most recent raw sensor reading.
    • int offset — stores the calibration offset.
  3. Public Member Functions
    • void setRaw(int value)
      • Stores a new raw sensor reading.
    • void calibrate(int off)
      • Sets the calibration offset.
    • int read()
      • Returns the calibrated sensor value (rawValue + offset).
  4. Main Function Behavior
    • Read three integers from standard input in the following order:
      1. Initial raw sensor value
      2. Calibration offset
      3. New raw sensor value
    • Create a Sensor object.
    • Call setRaw() using the initial raw value.
    • Call calibrate() using the offset.
    • Call setRaw() again using the new raw value.
    • Print the final calibrated sensor reading using read().

 

Input Format

Three signed integers provided via standard input, each separated by a newline:

raw
offset
newRaw

Output Format

A single integer printed to standard output:

calibrated_value 

Example Input

100
-5
120

Example Output

115

Explanation

The final calibrated reading is:

120 + (-5) = 115

Constraints

  • rawValue and offset must be private.
  • These variables may only be modified using class member functions.
  • Signed integer arithmetic is used.
  • No overflow handling is required beyond standard C++ int behavior.
  • Output must match exactly with no extra spaces or newlines.

 

 

 

Need Help? Refer to the Quick Guide below

In C, we use struct to bundle data together. However, the data is completely open—anyone can modify any field at any time, often leading to bugs (e.g., changing a buffer index without checking bounds).

In C++, a Class is an extension of a struct that adds Encapsulation. It bundles data (variables) and logic (functions) together, and uses Access Specifiers (private, public) to control who can see or touch that data.

Note: In C++, the only technical difference between a struct and a class is that members are public by default in a struct, and private by default in a class.

Syntax & Usage

1. Basic Declaration

Grouping hardware register definitions and the functions that use them into a single unit.

class Motor {
private:
    // Only functions inside this class can access these variables.
    // This protects the hardware state from accidental corruption.
    int pwm_pin;
    int speed; 

public:
    // The "Public API" - The rest of the code uses these functions.
    
    // Constructor (Initializes the object)
    Motor(int pin) {
        pwm_pin = pin;
        speed = 0;
        // Hardware init logic...
    }

    void setSpeed(int s) {
        if (s > 100) s = 100; // Safety check (Invariant)
        if (s < 0) s = 0;
        speed = s;
        // Apply to hardware...
    }
};

2. Usage

int main() {
    Motor m1(9);      // Create object 'm1' on pin 9

    m1.setSpeed(50);  // ✅ OK: Accessing public function
    
    // m1.speed = 200; // ❌ Error: 'speed' is private
}

Struct vs. Class (Memory Layout)

FeatureC structC++ class
Data AccessPublic (Open to everyone).Controlled (private/public).
LogicFunctions are separate.Functions are members.
MemorySum of members (+ padding).Identical (Sum of members + padding).
OverheadNone.Zero (unless Virtual Functions are used).

Relevance in Embedded/Firmware

1. Hardware Driver Encapsulation

This is the most important use case. You can hide the ugly, complex hardware register pointers inside the private section.

The Application Developer (User) just sees uart.init() and uart.send(). They don't need to know (and shouldn't touch) the UART->CR1 register directly.

2. Maintaining Invariants

An Invariant is a rule that must always be true (e.g., "Buffer index must never exceed 64").

If you use a C struct, a user can write buf.index = 100; and crash the system.

With a C++ class, you make index private. The user must call buf.advance(), which internally checks if (index < 64). This guarantees the system acts predictably.

3. Multiple Instances

In C, writing a driver that supports 3 UARTs often requires passing a context pointer (UART_Handle_t*) to every function.

In C++, you simply create 3 objects: UART u1, u2, u3;. The compiler handles the context (this pointer) automatically, making code cleaner.

Common Pitfalls (Practical Tips)

PitfallDetails
❌ The "Size" MythBeginners fear classes use more RAM. A class with two ints takes exactly 8 bytes, just like a struct with two ints. There is no hidden metadata unless you use virtual functions.
❌ Getters/Setters BloatDon't blindly make everything private and add getX()/setX() for every variable. That defeats the purpose. Only expose what the user needs to do their job.
❌ Public DataAvoid public member variables (e.g., public: int data;). If the user writes obj.data = 0;, your class doesn't know it changed, so it can't update dependent hardware states.
✅ Structs for DataUse struct for simple data containers (like a data packet or coordinate) where all fields are effectively public. Use class for objects that do things (Drivers, Managers).