Bundle data and behavior into one structure: class, private/public, constructors, const methods and struct.
Until now, data and functions were separate. We kept a resistor's value in a double and the current calculation in a separate function. In large programs this scattering is a source of bugs. A class bundles related data (members) and the functions that work with that data (methods) into a single structure. A concrete instance created from a class is called an object.
Our first class: Resistor
#include <iomanip>
#include <iostream>
class Resistor {
public:
// Constructor: runs when the object is created
Resistor(double ohm, double tolerance = 5.0)
: ohm_(ohm), tolerance_(tolerance) {}
double value() const { return ohm_; }
double current(double volt) const { return volt / ohm_; }
double power(double volt) const {
double i = current(volt);
return volt * i;
}
void print() const {
std::cout << ohm_ << " ohm (+-" << tolerance_ << "%)\n";
}
private:
double ohm_;
double tolerance_;
};
struct Reading {
int minute;
double temperature;
};
int main() {
Resistor r1(220);
r1.print();
std::cout << std::fixed << std::setprecision(4);
std::cout << "I = " << r1.current(5.0) << " A\n";
std::cout << "P = " << r1.power(5.0) << " W\n";
Reading o{10, 23.5};
std::cout << "t=" << o.minute << " min, " << o.temperature << " C\n";
return 0;
}
220 ohm (+-5%)
I = 0.0227 A
P = 0.1136 W
t=10 min, 23.5000 C
The parts
public and private
The public section is the interface open to the outside; only the class's own methods can access the private section. If you write r1.ohm_ = -5;, the compiler won't allow it. This rule is called encapsulation: anyone who wants to change the value from outside has to go through methods that you control. That way a resistor's value never turns into a nonsensical number. Putting _ at the end of member names is a common way to tell member variables apart from local variables.
Constructor
A constructor is a method with the same name as the class and no return type. It runs automatically when the object is created and gives the members their initial values. The ohm_(ohm), tolerance_(tolerance) part written after the colon is the member initializer list, and it is the right way to give initial values. You can give a constructor default arguments too: Resistor r1(220); automatically takes a tolerance of 5.
const methods
A const after the parentheses means "this method does not change the object". value(), current() and power() are like that. Only const methods can be called on constant objects or through const references, so mark every method that doesn't change anything as const.
struct
A struct is a class whose default access is public. It suits simple structures that only carry data and have no behavior (like Reading). It can be initialized with braces: Reading o{10, 23.5};.
Header and source files
In real projects the class declaration goes into resistor.h and the method bodies into resistor.cpp:
// resistor.h
#pragma once
class Resistor {
public:
explicit Resistor(double ohm);
double current(double volt) const;
private:
double ohm_;
};
// resistor.cpp
#include "resistor.h"
Resistor::Resistor(double ohm) : ohm_(ohm) {}
double Resistor::current(double volt) const {
return volt / ohm_;
}
To compile the two files together: g++ -std=c++17 main.cpp resistor.cpp -o program. #pragma once prevents the header from being included twice in the same file. explicit stops a single-parameter constructor from causing accidental automatic conversions.
Rule: make member variables private and expose only the methods that are needed. When you later want to change the internal structure, the code of those who use the class from outside won't break.
If the resistance value is zero or negative, current() gives a nonsensical result. In real code the constructor should check for this and (in C++, usually) throw an exception or clamp it to a valid value. Validation is the class's responsibility.
Try it yourself
- Add a
tolerance()method to theResistorclass. - Write a
Capacitorclass (capacitance, rated voltage). Itsenergy()method should calculate the formula0.5 * C * V * V. - Write a free function that returns the series sum of two
Resistorobjects. - Split the class into a header and a source file and compile them together.
// Mini quiz
Click an option; you will see right away, with the reason, whether it is correct or not.
Mark it when you finish: your progress is saved and you earn +20 XP.
Tip: ← → keys let you move between lessons.