반응형
시나리오
STL에 stack이 존재하지만 stack을 한번 만들어보자. 기존 list는 양쪽 방향으로 쓰기가 가능하다. 이 양쪽 방향 쓰기를 단방향 쓰기로 만들어준다면 stack처럼 사용할 수 있을 것이다. 또한 list의 함수 이름을 stack처럼 보이도록 변경해주면 될 것이다.
#include <iostream>
#include <list>
#include <vector>
#include <deque>
using namespace std;
template<typename T> class Stack : public list<T>
{
public:
void push(const T& a) { list<T>::push_back(a); }
void pop() { list<T>::pop_back(); }
T& top() { return list<T>::back(); }
};
int main()
{
Stack<int> s;
s.push(10);
s.push(20);
cout << s.top() << endl;
}
위의 구현에서 list::push_back()과 pop_back()이 각각 push()와 pop()으로 변경 되었다. 하지만 list를 그대로 상속 했기에 Stack 타입임에도 불구하고 다음과 같이 list의 멤버 함수를 직접 호출이 가능한 상태이다.
int main()
{
Stack<int> s;
s.push(10);
s.push(20);
cout << s.top() << endl;
// stack으로 약속하고 사용하려고 만들었는데 사용자가 list의 함수를 사용한다면?
// 문제 없이 사용할 수 있다. 이것은 문제다.
s.push_front(20);
}
사용자가 Stack 객체에서 list의 멤버들을 사용할 수 없도록 할 수 없을까?
해결 방법 1
list를 private로 상속한다.
// 해결방법1 (private 상속)
// list의 속성을 받을 수 있는 장점
template<typename T> class Stack1 : private list<T>
{
public:
void push(const T & a) { list<T>::push_back(a); }
void pop(const T & a) { list<T>::pop_back(a); }
T& top() { return list<T>::back(); }
};
이 경우 push_front를 호출하면 에러가 발생하여 사용자는 이 함수를 사용할 수 없다.
Stack1<int> s1;
s1.push(10);
s1.push(20);
//s1.push_front(20); // error!
해결 방법 2
list를 포함관계로 만들어준다.
// 해결방법2 (포함으로 변경)
// 완전히 List의 멤버를 폐쇄적으로 사용할 수 있다.
template<typename T> class Stack2
{
list<T> lst;
public:
void push(const T& a) { lst.push_back(a); }
void pop() { lst.pop_back(); }
T& top() { return lst.back(); }
};
이 경우, list의 객체가 완전히 감추어졌기 때문에 외부에서 push_front를 호출 할 수 없다.
Stack2<int> s2;
s2.push(10);
s2.push(20);
// s2.push_front(20); //error
사용 편의를 위해 확장
// Stack2의 확장,
// 어떤 컨테이너를 기반으로 확장할 것인지도 외부에서 결정해줄 수 있다. (기본값 deque제공)
template<typename T, typename C = deque<T> > class Stack3
{
C lst;
public:
void push(const T& a) { lst.push_back(a); }
void pop() { lst.pop_back(); }
T& top() { return lst.back(); }
};
Template 의 두번째 인자로 컨테이너의 타입도 결정해줄 수 있다. 지정해 주지 않는다면 deque로 사용된다. 이에 대한 사용은 다음과 같다.
Stack3<int, list<int>> s3;
Stack3<int, vector<int>> s4;
Stack3<int> s5;
Container Adapter
Sequence Container의 인터페이스를 수정해서 stack, queue, priority_queue를 제공한다.
위의 예제에서 "해결방법2"의 Stack2와 "사용 편의를 위한 확장"의 Stack3의 경우 포인터를 받지 않으므로 클래스 어뎁터이다.
반응형
'프로그래밍 이야기 > C++ 기초' 카테고리의 다른 글
[Design Pattern] Bridge (0) | 2021.02.02 |
---|---|
[DesignPattern] Facade (0) | 2021.01.19 |
[C++]Design Pattern - Adapter (0) | 2020.12.30 |
[게임이론] 벡터-내적의 활용 (0) | 2020.12.26 |
[C++]Design Pattern - Decorator Pattern (0) | 2020.12.18 |