Convert the incompatible interface of a class into another interface compatible with clients.
A client calls operations on an adapter object, which in turn forwards the call on to the adaptee.
The interface of std::deque<T> is (partially) adapted to support the interface of a queue. A queue typically supports, among other operations, push, pop, front and back operations. Whereas std::deque<> supports, among others, push_front, push_back, pop_font, pop_back, etc. Note how Queue<T>::push(x) calls std::deque<T>::push_back(x).
/* Adapter: Adapts the interface of adaptee to an interface acceptable by the client
In this example, the client expects a queue to support push, pop, front, and back operations.
A std::deque is therefore adapted to the behavior of a queue by wrapping the deque operations
with the expected interface. */
template<typename T>
class Queue
{
// Public Interface
public:
void push( const T& x)
{
m_deque.push_back( x );
}
T pop()
{
// Check container is not empty
if (m_deque.empty())
throw QueueEmpty();
// Get first element from deque and pop it form the front
T element( m_deque.front() );
m_deque.pop_front();
return element;
}
T& front()
{
// Check container is not empty
if (m_deque.empty())
throw QueueEmpty();
return m_deque.front();
}
T& back()
{
// Check container is not empty
if (m_deque.empty())
throw QueueEmpty();
return m_deque.back();
}
// Data members
private:
std::deque<T> m_deque;
};
class QueueEmpty : std::exception
{
public:
virtual const char *what() const throw()
{
return "Queue is empty";
}
};
int main(int argc, char* argv[])
{
try
{
// Push 3 items
Queue<int> q;
q.push( 10 );
q.push( 20 );
q.push( 30 );
std::cout << "front is: " << q.front() << std::endl;
std::cout << "back is: " << q.back() << std::endl;
// Pop 4 items
q.pop();
q.pop();
q.pop();
q.pop(); // throws exception. Queue is empty
}
catch( const QueueEmpty& e)
{
std::cout << e.what();
}
return 0;
}
Inheritance
Containment