//#include <iostream>
// using namespace std;
--
스택을 만들어 봅시다
oop : 잘못쓰기 어렵게 만들어라
--
// 버전10. 숙제 : 버전8의 스택을 내부자료구조를 싱글링크드리스트 방식의 template으로 설계해 보세요.
// 버전9. 잘만드는 사람이 stack을 만들어주면 좋지 않을까?? 이미 표준에 있다.
// STL(Standard Template Library)
// 결론 : STL의 다양한 클래스에는 제거와 리턴을 동시에 하는 함수는 거의 없다.
--
#include <iostream>
#include <stack>
using namespace std;
int main()
{
stack<int> s;
s.push( 10 );
s.push( 20 );
// 20, 10을 화면에 모두 출력해 보세요.
cout << s.top() << endl;
s.pop();
cout << s.top() << endl;
}
--
// 버전8. 최적화 - 성능을 향상시켜보자.
--
template<typename T> struct Stack
{
private :
T* buff;
int index;
public :
Stack( T sz = 100) {
index = 0;
buff = new T[ sz ];
}
~Stack() { delete[] buff; }
void Push(const T& a ) { buff[index++] = a; }
// 제거와 리턴을 동시에 하면, 참조를 리턴할 수 없다. 결국 임시객체가 리턴되므로 성능이 저하된다. = java
// T Pop() { return buff[--index]; }
// 제거와 리턴을 분리하자. = c++
void Pop() { --index; } // 제거만..
T& Top() { return buff[index]; } // 리턴만.. 참조리턴이 가능해진다.
};
int main()
{
Stack<int> s1(100); // 클래스 템플릿은 반드시 타입을 지정해야 합니다.
s1.Push( 10 );
s1.Push( 20 );
cout << s1.Top() << endl;
s1.Pop();
cout << s1.Top() << endl;
// cout << s2.Pop() << endl;
}
--
// 버전7. 다양한 타입에 대해서 자동으로 Stack 구조체가 Code 생성되게 하자 - template 도입(코드생성기)
// 어디를 바꿔야 하는지 잘 생각하자,
--
template<typename T> struct Stack
{
private :
T* buff;
int index;
public :
Stack( T sz = 100) {
index = 0;
buff = new T[ sz ];
}
~Stack() { delete[] buff; }
void Push( T a ) { buff[index++] = a; }
T Pop() { return buff[--index]; }
};
int main()
{
Stack<int> s1(100); // 클래스 템플릿은 반드시 타입을 지정해야 합니다.
Stack<double> s2;
s1.Push( 10 );
cout << s1.Pop() << endl;
// cout << s2.Pop() << endl;
}
--
// 버전6. 내부자료구조의 변경 - 동적메모리 할당./
--
struct Stack
{
private :
int* buff;
int index;
public :
// 생성자 : 구조체(클래스)이름과 동일한 함수, 객체를 생성하면 자동으로 호출된다.
Stack( int sz = 100) {
index = 0;
buff = new int[ sz ];
}
// 소멸자 : 객체가 파괴될 때, 자동으로 호출된다 => 여기서 객체가 사용한 자원을 해지한다.
~Stack() { delete[] buff; }
void Push( int a ) { buff[index++] = a; } // 버전6의 문제점, 타입이 항상 int ???
int Pop() { return buff[--index]; }
};
int main()
{
Stack s1(100); // 주면 주는거고,
Stack s2(); // 안주면 기본값으로 내가줄게.
s1.Push( 10 );
cout << s1.Pop() << endl;
//cout << s2.Pop() << endl;
}
--
// 버전5. 객체의 초기화를 자동으로 되게 하자 => 생성자 도입
--
struct Stack
{
private :
int buff[10]; // 맴버 data // 버전5의 문제점, 항상10개???
int index;
public :
// 생성자 : 구조체(클래스)이름과 동일한 함수, 객체를 생성하면 자동으로 호출된다.
Stack() { index = 0; }
void Push( int a ) { buff[index++] = a; }
int Pop() { return buff[--index]; }
};
int main()
{
Stack s1, s2;
// s1.init();
s1.Push( 10 );
cout << s1.Pop() << endl;
}
--
// 버전4. 객체의 상태를 외부에 직접 노출하면 잘못된 사용으로 객체가 불안해 진다.
// 외부에 잘못된 사용으로 부터 객체를 보호해야 한다.
// 용어 : 정보은닉, 좁은의미의 캡슐화
--
struct Stack
{
private :
int buff[10]; // 맴버 data
int index;
public :
void init() { index = 0; } // 맴버함수 : 맴버data에 직접 접근할 수 있다.
void Push( int a ) { buff[index++] = a; }
int Pop() { return buff[--index]; }
};
int main()
{
Stack s1, s2;
s1.init(); // 버전4의 문제점. 항상 직접 초기화를 해주어야 하나???
s1.Push( 10 );
// s1.index = 100; // error. private를 외부에서 직접 접근할 수 없다.
cout<< s1.Pop() << endl;
}
--
// 버전3. 상태를 나타내는 date와 상태를 조작하는 함수를 묶자 = > 넓은 의미의 캡슐화
--
struct Stack
{
int buff[10]; // 맴버 data
int index;
void init() { index = 0; } // 맴버함수 : 맴버data에 직접 접근할 수 있다.
void Push( int a ) { buff[index++] = a; }
int Pop() { return buff[--index]; }
};
int main()
{
Stack s1, s2;
s1.init();
s1.Push( 10 );
s1.index = 100; // 버전3의 문제점... 스택이 깨진다 : 함수만 쓰면 되는데, 가져다 쓸 수 없게끔 해야 한다.
cout<< s1.Pop() << endl;
}
--
// 버전2. 스택이라는 타입을 먼저 설계하자 - c 구조체 사용( c로 만들수 있는 최대 )
--
struct Stack
{
int buff[10];
int index;
};
void init( Stack* this ) { this->index = 0; } // 맴버함수호출의 원리..
void push( Stack* s, int a ) { s->buff[ s-> index++] = a; }
int pop( Stack* s) { return s->buff[--(s->index)]; }
int main()
{
Stack s1, s2; // stack 2개
init(&s1);
push(&s1, 10);
cout << pop(&s1) << endl;
}
--
// 버전1. 전역변수 사용 - 문제점 : 스택이 2개 필요하면 ???
--
int buff[10];
int index = 0;
void push( int a ) { buff[index++] = a; }
int pop() { return buff[--index]; }
int main()
{
push(10);
push(20);
cout << pop() << endl;
}
--

