Comparing OOP in Rust, Java, and C++

oops concept

Comparing OOP in Rust, Java, and C++

Object-Oriented Programming (OOP) has been a cornerstone of software design for decades. It organizes code around objects—bundles of data (state) and behavior (methods)—to make systems more modular, maintainable, and scalable.
While OOP principles are consistent, different languages approach them in very different ways. In this article, we’ll explore Java, C++, and Rust—three powerful languages with distinct OOP philosophies.

Core OOP Concepts

We’ll use five core OOP pillars as our comparison framework:

  1. Encapsulation – Hiding internal state and exposing controlled interfaces.
  2. Inheritance – Sharing structure/behavior across related types.
  3. Polymorphism – Treating different types through a common interface.
  4. Abstraction – Modeling complex systems with simplified representations.
  5. Memory Management – How object lifetimes and resources are handled.

Encapsulation

LanguageHow It’s DoneExample Highlights
Javaprivate, protected, public access modifiers; getters/setters are commonEnforced by JVM; true private fields
C++Same modifiers; can be bypassed via pointers; friend keywordLess strict; more freedom to break encapsulation
Rustpub keyword controls module-level visibility; no “class” but struct + implPrivacy is module-based, no “protected” keyword

Inheritance

LanguageApproach
JavaSingle inheritance (extends) + multiple interfaces
C++Multiple inheritance (can be risky); virtual inheritance to resolve diamond problem
RustNo inheritance; favors composition and traits

Polymorphism (Example)

Java:

javaCopyEditinterface Shape {
void draw();
}

class Circle implements Shape {
public void draw() { System.out.println("Drawing circle"); }
}

Shape s = new Circle();
s.draw();

C++:

cppCopyEdit#include <iostream>
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() {}
};

class Circle : public Shape {
public:
void draw() override { std::cout << "Drawing circle\n"; }
};

Shape* s = new Circle();
s->draw();
delete s;

Rust:

rustCopyEdittrait Shape {
fn draw(&self);
}

struct Circle;

impl Shape for Circle {
fn draw(&self) { println!("Drawing circle"); }
}

fn draw_shape(s: &dyn Shape) {
s.draw();
}

let c = Circle;
draw_shape(&c);

Abstraction

LanguageMechanism
JavaAbstract classes and interfaces
C++Pure virtual functions and abstract base classes
RustTraits as behavior contracts; no abstract base types

Memory Management

LanguageMemory Model
JavaGarbage collection; objects live on the heap
C++Manual (new/delete) or smart pointers (std::unique_ptr)
RustOwnership and borrowing; memory freed automatically at scope end

Summary Table

ConceptJava (Pure OOP)C++ (Multi-paradigm)Rust (Traits + Composition)
EncapsulationStrong, enforcedFlexible, can be brokenModule-based
InheritanceSingle + interfacesMultiple inheritanceNone (composition)
PolymorphismInterfacesVirtual functionsTraits + dyn dispatch
AbstractionInterfaces, abstract classesAbstract base classesTraits
Memory MgmtGCManual or smart ptrsOwnership model

Which One Should You Use?

  • Choose Java if you want pure OOP, minimal memory concerns, and strong type safety with a large enterprise ecosystem.
  • Choose C++ if you need performance-critical systems, fine-grained control over memory, or want to mix paradigms.
  • Choose Rust if safety, concurrency, and modern design matter most, and you’re comfortable with composition over inheritance.

In short:

  • Java feels familiar and forgiving for OOP beginners.
  • C++ gives you ultimate flexibility—at the cost of complexity.
  • Rust challenges OOP traditions for the sake of safety and clarity.

Post Comment