[2026] C++ Adapter Pattern: Complete Guide | Interface Wrapping & Legacy Integration

[2026] C++ Adapter Pattern: Complete Guide | Interface Wrapping & Legacy Integration

이 글의 핵심

Adapter pattern in C++: object vs class adapter, payment/API examples, unique_ptr—bridge incompatible interfaces for legacy and third-party code with SEO-friendly keywords.

Structural patterns (Adapter, Decorator, Proxy, …) are surveyed in C++ structural patterns #19-2 and the overview #20-2. For a JS angle on wrapping APIs, see JavaScript patterns.

What is Adapter Pattern? why you need it

Problem Scenario: Incompatible Interfaces

Problem: The interface of an existing library is not compatible with my code. 아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// The interface my code expects
class MediaPlayer {
public:
    virtual void play(const std::string& filename) = 0;
};
// Existing library (not compatible)
class VLCPlayer {
public:
    void playVLC(const std::string& filename) { /* ....*/ }
};
// How to use VLCPlayer as MediaPlayer?

Solution: Adapter Pattern converts interfaces. Adapter implements the Target interface and calls Adaptee internally. 아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Adapter
// 타입 정의
class VLCAdapter : public MediaPlayer {
public:
    VLCAdapter(std::unique_ptr<VLCPlayer> player)
        : vlc(std::move(player)) {}
    
    void play(const std::string& filename) override {
vlc->playVLC(filename);  // interface conversion
    }
    
private:
    std::unique_ptr<VLCPlayer> vlc;
};

Key Concept: Adapter Pattern acts as a bridge to bridge incompatible interfaces. This is an essential pattern when integrating legacy systems or using third-party libraries.

index

  1. Object Adapter
  2. Class adapter
  3. Legacy code integration
  4. Frequently occurring problems and solutions
  5. Production Patterns
  6. Complete example: Payment system

1. object adapter

An object adapter wraps an Adaptee using composition. This is the most common and recommended method.

Combination method

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <memory>
#include <string>
class MediaPlayer {
public:
    virtual void play(const std::string& filename) = 0;
    virtual ~MediaPlayer() = default;
};
class VLCPlayer {
public:
    void playVLC(const std::string& filename) {
        std::cout << "Playing VLC: " << filename << '\n';
    }
};
class MP4Player {
public:
    void playMP4(const std::string& filename) {
        std::cout << "Playing MP4: " << filename << '\n';
    }
};
class VLCAdapter : public MediaPlayer {
public:
    VLCAdapter() : vlc(std::make_unique<VLCPlayer>()) {}
    
    void play(const std::string& filename) override {
        vlc->playVLC(filename);
    }
    
private:
    std::unique_ptr<VLCPlayer> vlc;
};
class MP4Adapter : public MediaPlayer {
public:
    MP4Adapter() : mp4(std::make_unique<MP4Player>()) {}
    
    void play(const std::string& filename) override {
        mp4->playMP4(filename);
    }
    
private:
    std::unique_ptr<MP4Player> mp4;
};
int main() {
    std::unique_ptr<MediaPlayer> player;
    
    player = std::make_unique<VLCAdapter>();
    player->play("movie.vlc");
    
    player = std::make_unique<MP4Adapter>();
    player->play("movie.mp4");
}

2. class adapter

Class adapters are a way to use multiple inheritance. This is possible in C++, but is less flexible than an object adapter.

Multiple inheritance method

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <string>
class MediaPlayer {
public:
    virtual void play(const std::string& filename) = 0;
    virtual ~MediaPlayer() = default;
};
class VLCPlayer {
public:
    void playVLC(const std::string& filename) {
        std::cout << "Playing VLC: " << filename << '\n';
    }
};
// class adapter (multiple inheritance)
class VLCAdapter : public MediaPlayer, private VLCPlayer {
public:
    void play(const std::string& filename) override {
playVLC(filename);  // call directly
    }
};
int main() {
    MediaPlayer* player = new VLCAdapter();
    player->play("movie.vlc");
    delete player;
}

Advantage: No need to store Adaptee object. Disadvantage: Multiple inheritance, not possible if Adaptee is final.

3. Legacy code integration

The Adapter Pattern shines when it comes to integrating legacy systems into a modern codebase. You can use the new interface without modifying existing code.

Old APIs into modern interfaces

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <string>
#include <memory>
// Legacy API (C style)
class LegacyRectangle {
public:
    void draw(int x1, int y1, int x2, int y2) {
        std::cout << "Legacy: Rectangle from (" << x1 << "," << y1 
                  << ") to (" << x2 << "," << y2 << ")\n";
    }
};
// modern interface
class Shape {
public:
    virtual void draw() = 0;
    virtual ~Shape() = default;
};
class Rectangle : public Shape {
public:
    Rectangle(int x, int y, int w, int h)
        : x_(x), y_(y), width_(w), height_(h) {}
    
    void draw() override {
        std::cout << "Modern: Rectangle at (" << x_ << "," << y_ 
                  << ") size " << width_ << "x" << height_ << '\n';
    }
    
private:
    int x_, y_, width_, height_;
};
// Adapter
class LegacyRectangleAdapter : public Shape {
public:
    LegacyRectangleAdapter(int x, int y, int w, int h)
        : x_(x), y_(y), width_(w), height_(h),
          legacy(std::make_unique<LegacyRectangle>()) {}
    
    void draw() override {
        legacy->draw(x_, y_, x_ + width_, y_ + height_);
    }
    
private:
    int x_, y_, width_, height_;
    std::unique_ptr<LegacyRectangle> legacy;
};
int main() {
    std::unique_ptr<Shape> shape1 = std::make_unique<Rectangle>(10, 20, 100, 50);
    shape1->draw();
    
    std::unique_ptr<Shape> shape2 = std::make_unique<LegacyRectangleAdapter>(10, 20, 100, 50);
    shape2->draw();
}

4. Frequently occurring problems and solutions

Issue 1: Memory leak

Symptom: Memory leak. Cause: Use of raw pointer. 아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ❌ Incorrect use
class Adapter {
Adaptee* adaptee;  // who delete?
};
// ✅ Correct use
class Adapter {
    std::unique_ptr<Adaptee> adaptee;
};

Issue 2: Bi-directional adapter

Symptom: Cyclodependency. Cause: Convert A to B and B to A. 아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ✅ SOLVED: Common interface
class CommonInterface {
    virtual void operation() = 0;
};
class AdapterA : public CommonInterface { /* ....*/ };
class AdapterB : public CommonInterface { /* ....*/ };

5. production pattern

Pattern 1: Combined with Factory

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class MediaPlayerFactory {
public:
    static std::unique_ptr<MediaPlayer> create(const std::string& type) {
        if (type == "vlc") {
            return std::make_unique<VLCAdapter>();
        } else if (type == "mp4") {
            return std::make_unique<MP4Adapter>();
        }
        return nullptr;
    }
};
auto player = MediaPlayerFactory::create("vlc");
player->play("movie.vlc");

Pattern 2: Template Adapter

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

template<typename Adaptee>
class GenericAdapter : public MediaPlayer {
public:
    GenericAdapter() : adaptee(std::make_unique<Adaptee>()) {}
    
    void play(const std::string& filename) override {
        adaptee->playSpecific(filename);
    }
    
private:
    std::unique_ptr<Adaptee> adaptee;
};

6. Complete example: payment system

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <memory>
#include <string>
class PaymentProcessor {
public:
    virtual bool processPayment(double amount) = 0;
    virtual ~PaymentProcessor() = default;
};
// Legacy PayPal API
class PayPalAPI {
public:
    bool sendPayment(double dollars) {
        std::cout << "PayPal: Processing $" << dollars << '\n';
        return true;
    }
};
// Legacy Stripe API
class StripeAPI {
public:
    bool charge(int cents) {
        std::cout << "Stripe: Charging " << cents << " cents\n";
        return true;
    }
};
// New Square API
class SquareAPI {
public:
    bool makePayment(const std::string& amount) {
        std::cout << "Square: Payment of " << amount << '\n';
        return true;
    }
};
// Adapters
class PayPalAdapter : public PaymentProcessor {
public:
    PayPalAdapter() : paypal(std::make_unique<PayPalAPI>()) {}
    
    bool processPayment(double amount) override {
        return paypal->sendPayment(amount);
    }
    
private:
    std::unique_ptr<PayPalAPI> paypal;
};
class StripeAdapter : public PaymentProcessor {
public:
    StripeAdapter() : stripe(std::make_unique<StripeAPI>()) {}
    
    bool processPayment(double amount) override {
        int cents = static_cast<int>(amount * 100);
        return stripe->charge(cents);
    }
    
private:
    std::unique_ptr<StripeAPI> stripe;
};
class SquareAdapter : public PaymentProcessor {
public:
    SquareAdapter() : square(std::make_unique<SquareAPI>()) {}
    
    bool processPayment(double amount) override {
        return square->makePayment("$" + std::to_string(amount));
    }
    
private:
    std::unique_ptr<SquareAPI> square;
};
class PaymentService {
public:
    PaymentService(std::unique_ptr<PaymentProcessor> processor)
        : processor_(std::move(processor)) {}
    
    void checkout(double amount) {
        std::cout << "Processing checkout for $" << amount << '\n';
        if (processor_->processPayment(amount)) {
            std::cout << "Payment successful!\n\n";
        } else {
            std::cout << "Payment failed!\n\n";
        }
    }
    
private:
    std::unique_ptr<PaymentProcessor> processor_;
};
int main() {
    PaymentService service1(std::make_unique<PayPalAdapter>());
    service1.checkout(99.99);
    
    PaymentService service2(std::make_unique<StripeAdapter>());
    service2.checkout(49.50);
    
    PaymentService service3(std::make_unique<SquareAdapter>());
    service3.checkout(29.99);
}

organize

conceptDescription
Adapter Patternconvert interface
PurposeIntegration of incompatible interfaces
StructureTarget, Adapter, Adaptee
AdvantagesLegacy Integration, OCP Compliance, Reusability
Disadvantagesclass increment, indirect reference
Use CaseLegacy integrations, third-party libraries, API conversions
Adapter Pattern is an essential pattern to unify incompatible interfaces.

FAQ

Q1: When do I use the Adapter Pattern?

A: Used to integrate legacy code, use third-party libraries, and resolve interface inconsistencies.

Q2: Object adapter vs class adapter?

A: Object adapter combination (recommended), Class adapter multiple inheritance (C++ possible).

Q3: What is the difference from Decorator?

A: Adapter focuses on interface conversion, Decorator focuses on feature addition.

Q4: What is the difference from Facade?

A: Adapter focuses on single class transformation, Facade focuses on subsystem simplification.

Q5: What is the performance overhead?

A: 1 indirect reference, negligible.

Q6: What are the Adapter Pattern learning resources?

A:

  • “Design Patterns” by Gang of Four
  • “Head First Design Patterns” by Freeman & Freeman
  • Refactoring Guru: Adapter Pattern One-Line Summary: The Adapter Pattern allows you to integrate incompatible interfaces. Next, it would be a good idea to read Proxy Pattern.

Good article to read together (internal link)

Here’s another article related to this topic.

Practical tips

These are tips that can be applied right away in practice.

Debugging tips

  • If you run into a problem, check the compiler warnings first.
  • Reproduce the problem with a simple test case

Performance Tips

  • Don’t optimize without profiling
  • Set measurable indicators first

Code review tips

  • Check in advance for areas that are frequently pointed out in code reviews.
  • Follow your team’s coding conventions

Practical checklist

This is what you need to check when applying this concept in practice.

Before writing code

  • Is this technique the best way to solve the current problem?
  • Can team members understand and maintain this code?
  • Does it meet the performance requirements?

Writing code

  • Have you resolved all compiler warnings?
  • Have you considered edge cases?
  • Is error handling appropriate?

When reviewing code

  • Is the intent of the code clear?
  • Are there enough test cases?
  • Is it documented? Use this checklist to reduce mistakes and improve code quality.

Keywords covered in this article (related search terms)

This article will be helpful if you search for C++, adapter, pattern, wrapper, interface, legacy, etc.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3