oop-patterns

pluginagentmarketplace's avatarfrom pluginagentmarketplace

Production-grade skill for Object-Oriented Programming in C++. Covers classes, inheritance, polymorphism, encapsulation, SOLID principles, and design patterns.

⭐1stars🔀0forks📁View on GitHub🕐Updated Dec 31, 2025

When & Why to Use This Skill

This production-grade Claude skill provides expert-level guidance for Object-Oriented Programming (OOP) in C++. It enables developers to implement robust software architectures using SOLID principles and industry-standard design patterns such as Singleton, Factory, and Observer. With support for code generation, refactoring, and troubleshooting, it ensures high-quality, maintainable C++ development according to modern best practices.

Use Cases

  • Architecting modular and scalable C++ systems by applying SOLID principles to minimize technical debt and improve maintainability.
  • Implementing thread-safe and efficient design patterns like Singleton, Strategy, and Observer for complex software components.
  • Refactoring legacy C++ codebases to resolve architectural flaws such as tight coupling, object slicing, and improper inheritance structures.
  • Generating production-ready boilerplate code for complex class hierarchies, ensuring correct usage of virtual destructors and encapsulation.
  • Troubleshooting advanced C++ design issues including the diamond problem and memory management in polymorphic interfaces.
# SKILLOOP Patterns
# Version3.0.0 | SASMP v1.3.0 Compliant | Production-Grade
nameoop-patterns
version"3.0.0"
description>
sasmp_version"1.3.0"
skill_version"3.0.0"
bonded_agentcpp-oop-agent
bond_typePRIMARY_BOND
categorylearning
typestring
requiredfalse
enum[explanation, code_example, uml, refactoring]
defaultcode_example
max_attempts3
backoffexponential
initial_delay_ms500
jittertrue
on_design_error"suggest_alternative_pattern"
on_violation"explain_principle_and_fix"

OOP Patterns Skill

Production-Grade Learning Skill | Object-Oriented Design

Master C++ OOP concepts and industry-standard design patterns.


The Four Pillars

1. Encapsulation

class BankAccount {
private:
    std::string id_;
    double balance_{0.0};  // Default member init

public:
    explicit BankAccount(std::string id) : id_(std::move(id)) {}

    // Read-only access
    [[nodiscard]] double balance() const { return balance_; }
    [[nodiscard]] const std::string& id() const { return id_; }

    // Controlled mutation with validation
    void deposit(double amount) {
        if (amount <= 0) {
            throw std::invalid_argument("Amount must be positive");
        }
        balance_ += amount;
    }

    bool withdraw(double amount) {
        if (amount <= 0 || amount > balance_) return false;
        balance_ -= amount;
        return true;
    }
};

2. Inheritance

// Abstract base class
class Shape {
protected:
    std::string name_;

public:
    explicit Shape(std::string name) : name_(std::move(name)) {}
    virtual ~Shape() = default;  // ALWAYS virtual destructor!

    // Pure virtual functions (interface)
    [[nodiscard]] virtual double area() const = 0;
    [[nodiscard]] virtual double perimeter() const = 0;

    // Non-virtual (shared behavior)
    [[nodiscard]] const std::string& name() const { return name_; }
};

class Circle final : public Shape {  // final prevents further inheritance
    double radius_;
public:
    explicit Circle(double r) : Shape("Circle"), radius_(r) {}

    [[nodiscard]] double area() const override {
        return std::numbers::pi * radius_ * radius_;
    }

    [[nodiscard]] double perimeter() const override {
        return 2 * std::numbers::pi * radius_;
    }
};

3. Polymorphism

// Runtime polymorphism via virtual functions
void printShape(const Shape& shape) {
    std::cout << shape.name() << ": area = " << shape.area() << "\n";
}

// Usage - same function, different behavior
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>(5.0));
shapes.push_back(std::make_unique<Rectangle>(3.0, 4.0));

for (const auto& shape : shapes) {
    printShape(*shape);  // Polymorphic dispatch
}

4. Abstraction

// Pure interface (all pure virtual)
class ILogger {
public:
    virtual ~ILogger() = default;
    virtual void log(std::string_view message) = 0;
    virtual void setLevel(int level) = 0;
};

// Multiple implementations
class ConsoleLogger : public ILogger {
public:
    void log(std::string_view message) override {
        std::cout << "[LOG] " << message << "\n";
    }
    void setLevel(int) override { }
};

class FileLogger : public ILogger {
    std::ofstream file_;
public:
    explicit FileLogger(const std::string& path) : file_(path) {}
    void log(std::string_view message) override {
        file_ << message << "\n";
    }
    void setLevel(int) override { }
};

SOLID Principles

Principle Summary C++ Example
Single Responsibility One class, one reason to change Separate User from UserSerializer
Open/Closed Open for extension, closed for modification Virtual functions, inheritance
Liskov Substitution Subtypes must be substitutable Square shouldn't inherit Rectangle
Interface Segregation Prefer small, specific interfaces Split IWorker into IWorkable, IFeedable
Dependency Inversion Depend on abstractions Inject IDatabase& not MySQLDatabase

Design Patterns

Factory Pattern

class ShapeFactory {
public:
    static std::unique_ptr<Shape> create(std::string_view type, double param) {
        if (type == "circle") {
            return std::make_unique<Circle>(param);
        }
        if (type == "square") {
            return std::make_unique<Square>(param);
        }
        throw std::invalid_argument("Unknown shape type");
    }
};

// Usage
auto shape = ShapeFactory::create("circle", 5.0);

Singleton Pattern (Thread-Safe)

class Logger {
private:
    Logger() = default;

public:
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

    static Logger& instance() {
        static Logger instance;  // Thread-safe in C++11
        return instance;
    }

    void log(std::string_view msg) { std::cout << msg << "\n"; }
};

Observer Pattern

class IObserver {
public:
    virtual ~IObserver() = default;
    virtual void onNotify(const std::string& event) = 0;
};

class Subject {
    std::vector<IObserver*> observers_;
public:
    void attach(IObserver* obs) { observers_.push_back(obs); }
    void detach(IObserver* obs) {
        observers_.erase(std::remove(observers_.begin(), observers_.end(), obs),
                        observers_.end());
    }
    void notify(const std::string& event) {
        for (auto* obs : observers_) {
            obs->onNotify(event);
        }
    }
};

Strategy Pattern

class ICompressionStrategy {
public:
    virtual ~ICompressionStrategy() = default;
    virtual std::vector<uint8_t> compress(std::span<const uint8_t> data) = 0;
};

class ZipStrategy : public ICompressionStrategy {
public:
    std::vector<uint8_t> compress(std::span<const uint8_t> data) override {
        // ZIP compression
        return {};
    }
};

class Compressor {
    std::unique_ptr<ICompressionStrategy> strategy_;
public:
    void setStrategy(std::unique_ptr<ICompressionStrategy> s) {
        strategy_ = std::move(s);
    }
    std::vector<uint8_t> compress(std::span<const uint8_t> data) {
        return strategy_->compress(data);
    }
};

Troubleshooting

Issue Cause Solution
Object slicing Passing by value Use references/pointers
Memory leak Missing virtual destructor Add virtual ~Base() = default;
Diamond problem Multiple inheritance Use virtual inheritance
Tight coupling Direct dependencies Inject interfaces

Unit Test Template

#include <gtest/gtest.h>

TEST(ShapeTest, CircleArea) {
    Circle c(5.0);
    EXPECT_NEAR(c.area(), 78.5398, 0.0001);
}

TEST(ShapeTest, Polymorphism) {
    std::unique_ptr<Shape> shape = std::make_unique<Circle>(1.0);
    EXPECT_EQ(shape->name(), "Circle");
}

TEST(FactoryTest, CreateCircle) {
    auto shape = ShapeFactory::create("circle", 5.0);
    EXPECT_NE(shape, nullptr);
    EXPECT_EQ(shape->name(), "Circle");
}

C++ Plugin v3.0.0 - Production-Grade Learning Skill