Language[lang]
C++ OOPs concepts: the four ideas, with code
- Section
- Language [lang]
- Standard
- C++17
- Compilers
- MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2, Clang 23.1 (libc++)
- Published
- Length
- 8 min read
Abstract
OOPs in C++ is object-oriented programming: a program built from classes, types that bundle data with the functions that work on it, and objects, the values of those types. The four concepts are encapsulation (private data behind public functions), abstraction (an interface that hides how a type works, in C++ most plainly an abstract class), inheritance (a derived class built from a base) and polymorphism (one call, different code per type: at run time, a virtual call that runs the object’s own function).

OOPs in C++ means object-oriented programming: you build a program from classes, types that bundle data with the functions that work on it, and objects, the values of those types. The four OOPs concepts every list names are encapsulation, abstraction, inheritance and polymorphism. C++ supports all four and forces none of them on you.
Here are all four in one small program: an abstract Shape, two classes built on it, and a loop that asks each shape for its name and area.
#include <iostream>
#include <memory>
#include <string>
#include <vector>
constexpr double pi = 3.14159265358979;
class Shape {
public:
virtual ~Shape() = default;
virtual double area() const = 0;
virtual std::string name() const = 0;
};
class Circle : public Shape {
public:
explicit Circle(double radius) : radius_(radius) {}
double area() const override { return pi * radius_ * radius_; }
std::string name() const override { return "circle"; }
private:
double radius_;
};
class Rectangle : public Shape {
public:
Rectangle(double width, double height)
: width_(width), height_(height) {}
double area() const override { return width_ * height_; }
std::string name() const override { return "rectangle"; }
private:
double width_;
double height_;
};
int main() {
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>(1.0));
shapes.push_back(std::make_unique<Rectangle>(3.0, 2.0));
for (const auto& shape : shapes) {
std::cout << shape->name() << ": " << shape->area() << '\n';
}
}— end example]
It printed circle: 3.14159 and rectangle: 6.
The samples are C++17, built with MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2 and Clang 23.1 (libc++), and all four printed the same output and rejected the same code. override arrived in C++11; Since When lists the first compilers that took it.
What are a class and an object?
A class is a type you write once; an object is one value of that type, with its own copy of the data. Rectangle is the class here, and small and large are two objects of it:
class Rectangle {
public:
Rectangle(double width, double height)
: width_(width), height_(height) {}
double area() const { return width_ * height_; }
private:
double width_;
double height_;
};
int main() {
Rectangle small(3.0, 2.0); // one object of the class
Rectangle large(5.0, 4.0); // another, with its own data
std::cout << "small: " << small.area() << '\n'; // 6
std::cout << "large: " << large.area() << '\n'; // 20
}— end example]
It printed small: 6 and large: 20. Members under public: can be used by any code; members under private: only by the class’s own code. A class starts private until the first label, a struct starts public, and protected opens a member to derived classes as well. How to define a C++ class goes on to constructors, const member functions and header files.
What is encapsulation?
Encapsulation means the data is private and the class’s public functions are the only way to it, so the class can refuse a value that makes no sense. This Circle will not take a negative radius:
class Circle {
public:
double radius() const { return radius_; }
bool set_radius(double radius) {
if (radius < 0.0) {
return false; // refused: the old radius stays
}
radius_ = radius;
return true;
}
private:
double radius_ = 1.0; // only Circle's functions see it
};
// ...
Circle c;
std::cout << std::boolalpha;
bool ok = c.set_radius(-5.0);
std::cout << ok << ", radius " << c.radius() << '\n'; // false, 1
ok = c.set_radius(2.5);
std::cout << ok << ", radius " << c.radius() << '\n'; // true, 2.5— end example]
It printed false, radius 1, then true, radius 2.5. Code outside the class that writes c.radius_ = -5; does not compile on any of the four: Clang says 'radius_' is a private member of 'Circle', and GCC adds a note pointing at the public radius() reader. A class’s friend classes and functions are the one exception to the access rule.
What is abstraction?
Abstraction means showing what a type does and hiding how it does it. Its sharpest form in C++ is an abstract class: a class with at least one pure virtual function, a function declared with = 0 that names an operation and leaves derived classes to supply it. report works with any shape through that interface alone:
class Shape { // abstract: what a shape does
public:
virtual ~Shape() = default;
virtual double area() const = 0;
virtual std::string name() const = 0;
};
void report(const Shape& s) { // knows only the interface
std::cout << s.name() << ": " << s.area() << '\n';
}
// ...
report(Circle(1.0)); // circle: 3.14159
report(Rectangle(3.0, 2.0)); // rectangle: 6— end example]
It printed circle: 3.14159 and rectangle: 6. You cannot create an object of an abstract class: Shape s; fails on all four compilers, and MSVC says it most plainly, 'Shape': cannot instantiate abstract class. The C++ Core Guidelines make this the form of an interface in C.121: “If a base class is used as an interface, make it a pure abstract class.”
Abstraction is not encapsulation. Encapsulation guards the data; abstraction hides the how behind an interface. Circle does both, and report relies only on the second.
What is inheritance?
Inheritance builds a derived class from a base class: the derived class gets the base’s members and adds its own. class Circle : public Shape makes Circle a derived class of Shape, so it inherits describe(), written once in the base:
class Shape {
public:
// ...
void describe() const { // written once, in the base
std::cout << "a " << name() << " of area " << area() << '\n';
}
};
class Circle : public Shape { // a Circle is a Shape
// ...
private:
double radius_; // Circle's own data
};— end example]
Neither Circle nor Rectangle writes describe(), yet the circle’s call printed a circle of area 3.14159 and the rectangle’s a rectangle of area 6. describe() calls name() and area(), and each class’s own version ran: that is polymorphism. Inheritance in C++ covers what a derived class inherits, the base constructor and slicing.
What is polymorphism?
Polymorphism means one call, shape.area(), runs the function of the object’s own class. That is run-time polymorphism, the kind object-oriented code relies on; overloaded functions and templates give the compile-time kind. The run-time kind takes two things: the function is virtual in the base class, so a derived class can override it, and the call goes through a reference or pointer to the base.

Leave virtual out and the base’s version runs. PlainShape is the same pair without it:
class Shape {
public:
virtual ~Shape() = default;
virtual double area() const = 0; // virtual
};
// ...
class PlainShape {
public:
double area() const { return 0.0; } // not virtual
};
class PlainCircle : public PlainShape {
public:
explicit PlainCircle(double radius) : radius_(radius) {}
double area() const { return pi * radius_ * radius_; }
private:
double radius_;
};
void print_area(const Shape& shape) {
std::cout << "virtual: " << shape.area() << '\n';
}
void print_area(const PlainShape& shape) {
std::cout << "not virtual: " << shape.area() << '\n';
}
// ...
print_area(Circle(1.0)); // runs Circle::area
print_area(PlainCircle(1.0)); // runs PlainShape::area— end example]
Through a const Shape& the call printed 3.14159, the circle’s area; through a const PlainShape& it printed 0, the base’s. None of the four compilers warned about the second, at any warning level tried: a missing virtual is caught only where the derived function is marked override (PlainCircle::area with it fails on all four).
Write override (since C++11) on each function that replaces a virtual one: the compiler then checks the signature where you wrote it. Declare Circle::area without const and that line fails; Clang’s note names the cause, different qualifiers ('const' vs unqualified). Without override the same slip still failed here, because Shape::area is pure, but later and less clearly: as an abstract-class error at the line that creates a Circle.
Give a base class used this way a virtual destructor, as Shape has. Deleting a Circle through a Shape pointer without one is undefined behavior: the standard places no requirements on what happens. Do not count on a warning; GCC gave none when a std:: did the deleting. The rule is the Core Guidelines’ C.35: “A base class destructor should be either public and virtual, or protected and non-virtual.”
More in polymorphism in C++ and C++ virtual functions.
Is C++ only object-oriented?
No. C++ is a multi-paradigm language: one program can use free functions and templates beside its classes, and the standard library’s algorithms, such as std::sort, are not member functions of any class. Sorting the shapes by area takes a lambda, a function written in place, and no class of your own:
std::sort(shapes.begin(), shapes.end(),
[](const auto& a, const auto& b) {
return a->area() < b->area();
});— end example]
It printed the circle (3.14159) before the rectangle (6), though the rectangle went in first. A function template, total_area, written once for any container of pointers to shapes, added the areas up: total: 9.14159. Stroustrup’s FAQ describes C++ as supporting object-oriented programming among other styles, and names the main weakness of OOP as forcing too many problems into a hierarchy. Use one where types really share an interface, as the shapes do.
C++ OOPs concepts at a glance
| Concept | What it means | In C++ | Read next |
|---|---|---|---|
| Class and object | a type, and the values of it | class |
C++ class |
| Encapsulation | private data, public functions | private, public |
struct vs class |
| Abstraction | what a type does, not how | virtual, = 0 |
pure virtual functions |
| Inheritance | a derived class built from a base | : public |
inheritance in C++ |
| Polymorphism | one call, the object’s own function | virtual, override |
polymorphism in C++ |
| Constructors and destructors | set an object up, clean it up | Circle(double), ~Shape() |
constructors, destructors |
More answers on the core language are in Language.
Questions
What are the four pillars of OOPs in C++?
Encapsulation, abstraction, inheritance and polymorphism. Tutorials call them the four pillars; the C++ standard does not use the word. In C++ they are written with private members, abstract classes with pure virtual functions, derived classes and virtual functions.
How many OOPs concepts are there in C++?
Most lists give four: encapsulation, abstraction, inheritance and polymorphism. Lists that count class and object as concepts of their own give six. Bjarne Stroustrup’s FAQ describes object-oriented programming through three of them: encapsulation, inheritance and polymorphism.
What is the difference between abstraction and encapsulation?
Encapsulation guards the data: it is private, and the class’s own functions are the only way to it, so the class can refuse a bad value. Abstraction hides how a type works behind what it does; its plainest C++ form is an abstract class, whose pure virtual functions code can call without knowing which class is behind them.
What is the difference between a class and an object?
A class is a type: you write it once, and it says what data each object holds and which functions work on it. An object is one value of that type with its own copy of the data, so two Rectangle objects can have different sizes.
Is C++ fully object-oriented?
No. C++ is a multi-paradigm language: it supports object-oriented programming, and a program can also use free functions, templates and the standard library’s algorithms, which are not members of any class. A class hierarchy is one tool among several.
What is dynamic binding in C++?
Dynamic binding is another name for the virtual call: which function runs is chosen while the program runs, from the class of the object. It happens when a virtual function is called through a reference or pointer to the base class; without virtual, the base class’s function runs.
Sources
- Access specifierscppreference.com
- Abstract classcppreference.com
- virtual function specifiercppreference.com
- C.35: A base class destructor should be either public and virtual, or protected and non-virtualC++ Core Guidelines
- C.121: If a base class is used as an interface, make it a pure abstract classC++ Core Guidelines
- Bjarne Stroustrup’s FAQstroustrup.com