+
class is the language construct that makes object-oriented programming possible. A class binds data and the functions that operate on that data into a single unit, giving the programmer control over how state is created, accessed, modified, and destroyed. Every C++ program that goes beyond trivial procedural code depends on this mechanism.
class Person { ... };, you are telling the compiler that Person is a new type with its own size, layout, and set of legal operations — just as int and double are types with their own sizes and operations. The compiler uses the class definition to determine how much memory an object requires, where each data member sits within that memory, and which functions may be called on the object.
smallobj with one private data member and two public member functions. Although it is minimal, it demonstrates the syntax and general features of every C++ class: a data member that holds state, a function that sets the state, and a function that displays it.
// smallobj.cpp
// demonstrates a small, simple object
#include <iostream>
using namespace std;
class smallobj {
private:
int somedata; // class data
public:
void setdata(int d) { // member function to set data
somedata = d;
}
void showdata() { // member function to display data
cout << "Data is " << somedata << endl;
}
};
int main() {
smallobj s1, s2; // define two objects of class smallobj
s1.setdata(1066); // call member function to set data
s2.setdata(1776);
s1.showdata(); // call member function to display data
s2.showdata();
return 0;
}
s1 and s2 are two separate objects. Each has its own copy of somedata, so setting s1 to 1066 and s2 to 1776 does not create a conflict. Both objects share the same member function code — the compiler does not duplicate the function body for each object. Instead, each call implicitly passes a pointer to the calling object (the this pointer), which is how the function knows which object's data to access.
somedata is declared private. Code outside the class cannot read or modify it directly. The only way to interact with the data is through the public member functions setdata and showdata. This is encapsulation — the class controls its own invariants.
public — members are accessible from any part of the program. Public member functions form the class's interface: the set of operations that external code is allowed to use.
private — members are accessible only within the class itself. Data members are almost always private. This forces all access through member functions, which can validate inputs and maintain invariants.
protected — members are accessible within the class and within any class that derives from it. Protected access is relevant when you design class hierarchies for inheritance, a topic covered in a later module.
class is private. This is the only behavioral difference between class and struct in C++: a struct defaults to public.
~). Its purpose is to release any resources the object acquired during its lifetime — closing files, freeing memory, releasing network connections.
std::unique_ptr, std::shared_ptr) which manage heap-allocated memory automatically.
class FileLogger {
public:
FileLogger(const std::string& path)
: stream_{path, std::ios::app}
{
if (!stream_.is_open())
throw std::runtime_error("Cannot open log file: " + path);
}
~FileLogger() {
// stream_ closes automatically (RAII)
}
void log(const std::string& message) {
stream_ << message << '\n';
}
private:
std::ofstream stream_;
};
std::ofstream's own destructor close it. There is no manual close() call — the resource is tied to the object's lifetime. If a constructor is not provided, the compiler generates a default constructor that default-initializes each data member. If the class manages resources, you should always provide an explicit constructor and destructor.
::), they are external member functions and are not implicitly inline.
.cpp source file. This separation keeps the class declaration readable and enables independent compilation — changing a function body in the .cpp file does not force every translation unit that includes the header to recompile.
// Rectangle.h
class Rectangle {
public:
Rectangle(int width, int height);
int area() const;
void setValues(int width, int height);
private:
int width_;
int height_;
};
// Rectangle.cpp
#include "Rectangle.h"
Rectangle::Rectangle(int width, int height)
: width_{width}, height_{height} {}
int Rectangle::area() const {
return width_ * height_;
}
void Rectangle::setValues(int width, int height) {
width_ = width;
height_ = height;
}
Rectangle class above declares three member functions in the header. All three are defined externally in the source file using the Rectangle:: qualifier. The constructor uses a member initializer list (: width_{width}, height_{height}), which is the preferred way to initialize data members in modern C++ because it avoids default-constructing the member first and then assigning to it.
new or smart pointers). All objects of the same class share the same member function code.
Rectangle r1{10, 5}; // stack allocation
Rectangle r2{20, 3}; // separate object, separate data
auto r3 = std::make_unique<Rectangle>(7, 4); // heap allocation (RAII)
std::cout << r1.area() << '\n'; // 50
std::cout << r2.area() << '\n'; // 60
std::cout << r3->area() << '\n'; // 28
.) accesses members on stack-allocated objects. The arrow operator (->) accesses members through a pointer, including smart pointers. Both operators are used constantly in C++ code, and understanding when to use each is part of understanding object lifetime and ownership.
virtual, the runtime dispatches calls to the correct derived-class override based on the actual type of the object — this is polymorphism.
.cppm) exports the class declaration, and a module implementation unit contains the external definitions. The compilation model changes — no more include guards, no more repeated header parsing — but the fundamental class construct remains identical.
concept-constrained templates, allowing the compiler to produce clear error messages when a type does not meet a template's requirements. This makes generic programming with class types safer and more readable.
constexpr Expansion. More class member functions can now be evaluated at compile time. A constexpr constructor combined with constexpr member functions allows entire objects to be created and used during compilation, enabling compile-time validation and lookup tables with zero runtime cost.
this. The explicit object parameter feature (this auto&& self) allows a single member function definition to handle both const and non-const objects, reducing boilerplate in classes that previously required duplicate overloads.
this pointer, static members, and practical class design exercises. Each lesson builds on the concepts introduced here, so ensure you are comfortable with the material on this page before moving forward.