Object-oriented programming in C++ organizes code around classes and objects.
A class is a blueprint; an object is a real instance created from that blueprint.
The four core OOP ideas are encapsulation, abstraction, inheritance, and polymorphism.
Object-oriented programming, or OOP, is a programming style where we model real-world or logical entities as objects. Each object can store data and perform actions through functions.
C++ supports procedural programming like C, but it also supports object-oriented programming through classes, objects, constructors, access specifiers, inheritance, virtual functions, and more. OOP helps large programs stay organized because related data and behavior live together.
Beginners often confuse class and object. The class is only the design. The object is the actual thing created from that design.
| Concept | Meaning | Example |
|---|---|---|
| Class | Blueprint or template | class Student |
| Object | Instance created from a class | Student s1; |
| Data member | Variable inside a class | name, rollNo, marks |
| Member function | Function inside a class | display(), calculateGrade() |
A class combines data with operations that preserve valid state. Start with a BankAccount that owns a balance and exposes deposit and withdraw methods. Keep the balance private so callers cannot assign impossible values directly. Validate constructor arguments and every state-changing operation.
Constructors establish invariants, while destructors release owned resources. Prefer automatic objects and standard library types so RAII handles cleanup. Use const member functions for operations that do not modify observable state, pass large objects by const reference, and initialize members in the constructor initializer list.
Inheritance models an is-a relationship, but composition is often simpler. A Car has an Engine; it is not an Engine. Use virtual functions only when runtime polymorphism is required, add a virtual destructor to polymorphic base classes, and use override so the compiler verifies the intended method relationship.
The foundation of OOP is usually explained with four major pillars. These ideas help you design reusable and maintainable programs.
| Pillar | Meaning | C++ Feature |
|---|---|---|
| Encapsulation | Bind data and methods together and protect internal state | class, private, public, getters, setters |
| Abstraction | Show essential behavior and hide implementation details | public methods, abstract classes |
| Inheritance | Create a new class from an existing class | class Child : public Parent |
| Polymorphism | Same interface, different behavior | function overloading, overriding, virtual functions |
Access specifiers decide where class members can be used. They are central to encapsulation.
| Specifier | Access | Common Use |
|---|---|---|
| private | Only inside the same class | Protect data members |
| public | Accessible from outside the class | Expose useful methods |
| protected | Inside class and derived classes | Allow controlled inheritance access |
A constructor runs automatically when an object is created. It is commonly used to initialize data members. A destructor runs automatically when an object is destroyed. It is commonly used for cleanup.
This example shows class, object, private data, constructor, member functions, encapsulation, inheritance, and runtime polymorphism in one simple program.
#include <iostream>
#include <string>
using namespace std;
class Account {
private:
string owner;
double balance;
public:
Account(string ownerName, double openingBalance) {
owner = ownerName;
balance = openingBalance;
}
string getOwner() const {
return owner;
}
double getBalance() const {
return balance;
}
void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
bool withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
}
virtual void printAccountType() const {
cout << "General account" << endl;
}
virtual ~Account() {}
};
class SavingsAccount : public Account {
private:
double interestRate;
public:
SavingsAccount(string ownerName, double openingBalance, double rate)
: Account(ownerName, openingBalance), interestRate(rate) {}
void printAccountType() const override {
cout << "Savings account with interest rate "
<< interestRate << "%" << endl;
}
};
int main() {
SavingsAccount acc("Asha", 5000, 4.5);
acc.deposit(1000);
acc.withdraw(750);
cout << "Owner: " << acc.getOwner() << endl;
cout << "Balance: " << acc.getBalance() << endl;
Account* basePtr = &acc;
basePtr->printAccountType(); // runtime polymorphism
return 0;
}
Owner: Asha
Balance: 5250
Savings account with interest rate 4.5%
| OOP Concept | Where It Appears | Why It Matters |
|---|---|---|
| Class | Account and SavingsAccount | Groups related data and behavior |
| Object | SavingsAccount acc | Creates a usable account instance |
| Encapsulation | owner and balance are private | Protects data from direct external modification |
| Inheritance | SavingsAccount inherits Account | Reuses common account behavior |
| Polymorphism | virtual printAccountType() | Calls derived behavior through base pointer |
| Abstraction | deposit(), withdraw(), getBalance() | User calls simple methods without knowing internals |
OOP is useful when your program has entities with state and behavior. It is not required for every small program, but it becomes powerful as programs grow.
This page gives the big picture of OOP. The Classes and Objects page focuses more deeply on class syntax, object creation, constructors, destructors, getters, setters, and member functions.
Prefer the Rule of Zero: compose classes from std::string, std::vector, smart pointers, and other RAII types so compiler-generated copy, move, and destruction behavior is correct. When a class directly owns a raw resource, understand the Rule of Five and define or delete copy and move operations deliberately.
Decide whether the type has value semantics, unique identity, or shared ownership. Value types should copy predictably. Unique resources use std::unique_ptr, while shared_ptr should represent genuine shared lifetime rather than convenience. Avoid exposing owning raw pointers and unclear lifetime contracts.
Keep public interfaces small, exception guarantees documented, and dependencies injectable. Avoid deep inheritance trees and fragile base-class assumptions. Test invariants, copying and moving, invalid input, and polymorphic destruction. Performance decisions should follow measurement rather than premature manual memory management.
The methods preserve the balance invariant.
class BankAccount {
public:
explicit BankAccount(double opening) : balance_(opening) {
if (opening < 0) throw std::invalid_argument(\"negative balance\");
}
void deposit(double amount) {
if (amount <= 0) throw std::invalid_argument(\"invalid deposit\");
balance_ += amount;
}
bool withdraw(double amount) {
if (amount <= 0 || amount > balance_) return false;
balance_ -= amount;
return true;
}
double balance() const noexcept { return balance_; }
private:
double balance_;
};
unique_ptr controls lifetime and the base destructor is virtual.
class Shape {
public:
virtual ~Shape() = default;
virtual double area() const = 0;
};
class Circle final : public Shape {
public:
explicit Circle(double radius) : radius_(radius) {}
double area() const override {
return 3.141592653589793 * radius_ * radius_;
}
private:
double radius_;
};
std::unique_ptr<Shape> shape = std::make_unique<Circle>(2.0);
C++ supports object-oriented programming, but it is multi-paradigm. You can write procedural, object-oriented, generic, and functional-style C++.
A class is a blueprint. An object is an actual instance created from that blueprint.
Private data members prevent outside code from putting an object into an invalid state. Public methods can validate changes.
Explore 500+ free tutorials across 20+ languages and frameworks.