[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
- Object Adapter
- Class adapter
- Legacy code integration
- Frequently occurring problems and solutions
- Production Patterns
- 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
| concept | Description |
|---|---|
| Adapter Pattern | convert interface |
| Purpose | Integration of incompatible interfaces |
| Structure | Target, Adapter, Adaptee |
| Advantages | Legacy Integration, OCP Compliance, Reusability |
| Disadvantages | class increment, indirect reference |
| Use Case | Legacy 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.
- C++ Decorator Pattern Complete Guide | Dynamic addition and combination of functions
- Complete Guide to C++ Facade Pattern | Complex subsystems into one simple interface
- Complete Guide to C++ Bridge Pattern | Increasing scalability by separating implementation and abstraction
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.
Related articles
- C++ Decorator Pattern Complete Guide | Dynamic addition and combination of functions
- Complete Guide to C++ Command Pattern | Undo and macro system
- C++ CRTP Complete Guide | Static polymorphism and compile-time optimization
- Complete Guide to C++ Facade Pattern | Complex subsystems into one simple interface
- C++ Factory Pattern Complete Guide | Object creation encapsulation and extensibility