10장 템플릿과 표준 템플릿 라이브러리(STL) 명품 C++ 10장 템플릿과 표준 템플릿 라이브러리(STL)
함수의 매개 변수만 다르고 나머지 코드는 동일함 함수 중복의 약점 – 중복 함수의 코드 중복 #include <iostream> using namespace std; void myswap(int& a, int& b) { int tmp; tmp = a; a = b; b = tmp; } void myswap(double & a, double & b) { double tmp; int main() { int a=4, b=5; myswap(a, b); // myswap(int& a, int& b) 호출 cout << a << '\t' << b << endl; double c=0.3, d=12.5; myswap(c, d); // myswap(double& a, double& b) 호출 cout << c << '\t' << d << endl; 함수의 매개 변수만 다르고 나머지 코드는 동일함 동일한 코드 중복 작성 5 4 12.5 0.3
일반화와 템플릿 제네릭(generic) 또는 일반화 템플릿 템플릿 선언 함수나 클래스를 일반화시키고, 매개 변수 타입을 지정하여 틀에서 찍어 내듯이 함수나 클래스 코드를 생산하는 기법 템플릿 함수나 클래스를 일반화하는 C++ 도구 template 키워드로 함수나 클래스 선언 변수나 매개 변수의 타입만 다르고, 코드 부분이 동일한 함수를 일반화시킴 제네릭 타입 - 일반화를 위한 데이타 타입 템플릿 선언 템플릿을 선언하는 키워드 제네릭 타입을 선언하는 키워드 제네릭 타입 T 선언 template <class T> 또는 template <typename T> 3 개의 제네릭 타입을 가진 템플릿 선언 template <class T1, class T2, class T3> template <class T> void myswap (T & a, T & b) { T tmp; tmp = a; a = b; b = tmp; } 템플릿을 이용한 제네릭 함수 myswap
중복 함수들로부터 템플릿 만들기 사례 template <class T> void myswap(int & a, int & b) { int tmp; tmp = a; a = b; b = tmp; } 템플릿을 선언하는 키워드 제네릭 타입을 선언하는 키워드 제네릭 타입 T 선언 template <class T> void myswap (T & a, T & b) { T tmp; tmp = a; a = b; b = tmp; } 제네릭 함수 만들기(일반화) void myswap (double & a, double & b) { double tmp; tmp = a; a = b; b = tmp; } 템플릿을 이용한 제네릭 함수 중복 함수들
myswap(a, b) 호출에 필요한 함수 구체화 템플릿으로부터의 구체화 구체화(specialization) 템플릿의 제네릭 타입에 구체적인 타입 지정 템플릿 함수로부터 구체화된 함수의 소스 코드 생성 T에 int를 대입하여 구체화된 소스 코드 생성 template <class T> void myswap(T & a, T & b) { T tmp; tmp = a; a = b; b = tmp; } void myswap(int & a, int & b) { int tmp; tmp = a; a = b; b = tmp; } int main() { int a=4, b=5; myswap(a, b); 구체화 컴파일 후 실행 호출 int main() { int a=4, b=5; myswap(a, b); } myswap(a, b) 호출에 필요한 함수 구체화
제네릭 함수로부터 구체화된 함수 생성 사례 int a=4, b=5; myswap(a, b); void myswap(int & a, int & b) { int tmp; tmp = a; a = b; b = tmp; } T -> int template <class T> void myswap(T & a, T & b) { T tmp; tmp = a; a = b; b = tmp; } double c=0.3, d=12.5; myswap(c, d); void myswap(double & a, double & b) { double tmp; tmp = a; a = b; b = tmp; } T ->double char e=‘a’, f=‘k’; myswap(e, f); 제네릭 함수 void myswap(char & a, char & b) { char tmp; tmp = a; a = b; b = tmp; } T -> char 구체화 구체화된 버전의 C++ 소스 생성
예제 10–1 제네릭 myswap() 함수 만들기 #include <iostream> int main() { using namespace std; class Circle { int radius; public: Circle(int radius=1) { this->radius = radius; } int getRadius() { return radius; } }; template <class T> void myswap(T & a, T & b) { T tmp; tmp = a; a = b; b = tmp; } int main() { int a=4, b=5; myswap(a, b); cout << "a=" << a << ", " << "b=" << b << endl; double c=0.3, d=12.5; myswap(c, d); cout << "c=" << c << ", " << "d=" << d << endl; Circle donut(5), pizza(20); myswap(donut, pizza); cout << "donut반지름=" << donut.getRadius() << ", "; cout << "pizza반지름=" << pizza.getRadius()<< endl; } myswap(int& a, int& b) 함수 구체화 및 호출 myswap(double& a, double& b) 함수 구체화 및 호출 myswap(Circle& a, Circle& b) 함수 구체화 및 호출 a=5, b=4 c=12.5, d=0.3 donut반지름=20, pizza반지름=5
구체화 오류 제네릭 타입에 구체적인 타입 지정 시 주의 두 개의 매개 변수의 제네릭 타입 동일 template <class T> void myswap(T & a, T & b) int s=4; double t=5; myswap(s, t); 컴파일 오류. 템플릿으로부터 myswap(int &, double &) 함수를 구체화할 수 없다. 두 개의 매개 변수의 타입이 서로 다름
템플릿 장점과 제네릭 프로그래밍 템플릿 장점 템플릿 단점 제네릭 프로그래밍 함수의 재사용 포팅에 취약 높은 소프트웨어의 생산성과 유용성 템플릿 단점 포팅에 취약 컴파일러에 따라 지원하지 않을 수 있음 컴파일 오류 메시지 빈약, 디버깅에 많은 어려움 제네릭 프로그래밍 generic programming 일반화 프로그램이라고도 부름 제네릭 함수나 제네릭 클래스를 활용하는 프로그래밍 기법 C++에서 STL(Standard Template Library) 제공. 활용 보편화 추세 Java, C# 등 많은 언어에서 활용
예제 10–2 큰 값을 리턴하는 bigger() 함수 만들기 연습 #include <iostream> using namespace std; template <class T> T bigger(T a, T b) { // 두 개의 매개 변수를 비교하여 큰 값을 리턴 if(a > b) return a; else return b; } int main() { int a=20, b=50; char c='a', d='z'; cout << "bigger(20, 50)의 결과는 " << bigger(a, b) << endl; cout << "bigger('a', 'z')의 결과는 " << bigger(c, d) << endl; bigger(20, 50)의 결과는 50 bigger('a', 'z')의 결과는 z
예제 10–3 배열의 합을 구하여 리턴하는 제네릭 add() 함수 만들기 연습 #include <iostream> using namespace std; template <class T> T add(T data [], int n) { // 배열 data에서 n개의 원소를 합한 결과를 리턴 T sum = 0; for(int i=0; i<n; i++) { sum += data[i]; } return sum; // sum와 타입과 리턴 타입이 모두 T로 선언되어 있음 int main() { int x[] = {1,2,3,4,5}; double d[] = {1.2, 2.3, 3.4, 4.5, 5.6, 6.7}; cout << "sum of x[] = " << add(x, 5) << endl; // 배열 x와 원소 5개의 합을 계산 cout << "sum of d[] = " << add(d, 6) << endl; // 배열 d와 원소 6개의 합을 계산 sum of x[] = 15 sum of d[] = 23.7
예제 10-4 배열을 복사하는 제네릭 함수 mcopy() 함수 만들기 연습 #include <iostream> using namespace std; // 두 개의 제네릭 타입 T1, T2를 가지는 copy()의 템플릿 template <class T1, class T2> void mcopy(T1 src [], T2 dest [], int n) { // src[]의 n개 원소를 dest[]에 복사하는 함수 for(int i=0; i<n; i++) dest[i] = (T2)src[i]; // T1 타입의 값을 T2 타입으로 변환한다. } int main() { int x[] = {1,2,3,4,5}; double d[5]; char c[5] = {'H', 'e', 'l', 'l', 'o'}, e[5]; mcopy(x, d, 5); // int x[]의 원소 5개를 double d[]에 복사 mcopy(c, e, 5); // char c[]의 원소 5개를 char e[]에 복사 for(int i=0; i<5; i++) cout << d[i] << ' '; // d[] 출력 cout << endl; for(int i=0; i<5; i++) cout << e[i] << ' '; // e[] 출력 mcopy()의 T1은 int로, T2는 double로 구체화 mcopy()의 T1, T2 모두 char로 구체화 1 2 3 4 5 H e l l o
배열을 출력하는 print() 템플릿 함수의 문제점 #include <iostream> using namespace std; template <class T> void print(T array [], int n) { for(int i=0; i<n; i++) cout << array[i] << '\t'; cout << endl; } int main() { int x[] = {1,2,3,4,5}; double d[5] = { 1.1, 2.2, 3.3, 4.4, 5.5 }; print(x, 5); print(d, 5); char c[5] = {1, 2, 3, 4, 5}; print(c, 5); char로 구체화되면 숫자대신 문자가 출력되는 문제 발생! T가 char로 구체화되는 경우, 정수 1, 2, 3, 4, 5에 대한 그래픽 문자 출력 다음 화면: 함수중복으로 해결 print() 템플릿의 T가 int 타입으로 구체화 print() 템플릿의 T가 double 타입으로 구체화 print() 템플릿의 T가 char 타입으로 구체화
예제 10-5 템플릿 함수보다 중복 함수가 우선 #include <iostream> using namespace std; template <class T> void print(T array [], int n) { for(int i=0; i<n; i++) cout << array[i] << '\t'; cout << endl; } void print(char array [], int n) { // char 배열을 출력하기 위한 함수 중복 cout << (int)array[i] << '\t'; // array[i]를 int 타입으로 변환하여 정수 출력 int main() { int x[] = {1,2,3,4,5}; double d[5] = { 1.1, 2.2, 3.3, 4.4, 5.5 }; print(x, 5); print(d, 5); char c[5] = {1,2,3,4,5}; print(c, 5); 템플릿 함수와 중복된 print() 함수 중복된 print() 함수가 우선 바인딩 템플릿 print() 함수로부터 구체화 1 2 3 4 5 1.1 2.2 3.3 4.4 5.5 주목
제네릭 클래스 만들기 제네릭 클래스 선언 제네릭 클래스 구현 클래스 구체화 및 객체 활용 template <class T> class MyStack { int tos; T data [100]; // T 타입의 배열 public: MyStack(); void push(T element); T pop(); }; 제네릭 클래스 선언 제네릭 클래스 구현 클래스 구체화 및 객체 활용 template <class T> void MyStack<T>::push(T element) { ... } template <class T> T MyStack<T>::pop() { MyStack<int> iStack; // int 타입을 다루는 스택 객체 생성 MyStack<double> dStack; // double 타입을 다루는 스택 객체 생성 iStack.push(3); int n = iStack.pop(); dStack.push(3.5); double d = dStack.pop();
예제 10–6 제네릭 스택 클래스 만들기 3 3.5 a #include <iostream> using namespace std; template <class T> class MyStack { int tos;// top of stack T data [100]; // T 타입의 배열. 스택의 크기는 100 public: MyStack(); void push(T element); // element를 data [] 배열에 삽입 T pop(); // 스택의 탑에 있는 데이터를 data[] 배열에서 리턴 }; MyStack<T>::MyStack() { // 생성자 tos = -1; // 스택은 비어 있음 } void MyStack<T>::push(T element) { if(tos == 99) { cout << "stack full"; return; tos++; data[tos] = element; T MyStack<T>::pop() { T retData; if(tos == -1) { cout << "stack empty"; return 0; // 오류 표시 retData = data[tos--]; return retData; int main() { MyStack<int> iStack; // int 만 저장하는 스택 iStack.push(3); cout << iStack.pop() << endl; MyStack<double> dStack; // double 만 저장하는 스택 dStack.push(3.5); cout << dStack.pop() << endl; MyStack<char> *p = new MyStack<char>(); // char만 저장하는 스택 p->push('a'); cout << p->pop() << endl; delete p; } 3 3.5 a
예제 10–7 제네릭 스택의 제네릭 타입을 포인터나 클래스로 구체화하는 예(int*,Point객체,Point*,string) #include <iostream> #include <string> using namespace std; /* 이 부분에 예제 10-6에 작성한 MyStack 템플릿 클래스 코드가 생략되었음 */ class Point { int x, y; public: Point(int x=0, int y=0) { this->x = x; this->y = y; } void show() { cout << '(' << x << ',' << y << ')' << endl; } }; int main() { MyStack<int *> ipStack; // int* 만을 저장하는 스택 int *p = new int [3]; for(int i=0; i<3; i++) p[i] = i*10; // 0, 10, 20으로 초기화 ipStack.push(p); // 포인터 푸시 int *q = ipStack.pop(); // 포인터 팝 for(int i=0; i<3; i++) cout << q[i] << ' '; // 화면 출력 cout << endl; delete [] p; MyStack<Point> pointStack; // Point 객체 저장 스택 Point a(2,3), b; pointStack.push(a); // Point 객체 a 푸시. 복사되어 저장 b = pointStack.pop(); // Point 객체 팝 b.show(); // Point 객체 출력 MyStack<Point*> pStack; // Point* 포인터 스택 pStack.push(new Point(10,20)); // Point 객체 푸시 Point* pPoint = pStack.pop(); // Point 객체의 포인터 팝 pPoint->show(); // Point 객체 출력 MyStack<string> stringStack; // 문자열만 저장하는 스택 string s="c++"; stringStack.push(s); stringStack.push("java"); cout << stringStack.pop() << ' ‘; cout << stringStack.pop() << endl; } 0 10 20 (2,3) (10,20) java c++
예제 10–8 두 개의 제네릭 타입을 가진 클래스 만들기 #include <iostream> using namespace std; template <class T1, class T2> // 두 개의 제네릭 타입 선언 class GClass { T1 data1; T2 data2; public: GClass(); void set(T1 a, T2 b); void get(T1 &a, T2 &b); }; template <class T1, class T2> GClass<T1, T2>::GClass() { data1 = 0; data2 = 0; } void GClass<T1, T2>::set(T1 a, T2 b) { data1 = a; data2 = b; void GClass<T1, T2>::get(T1 & a, T2 & b) { a = data1; b = data2; int main() { int a; double b; GClass<int, double> x; x.set(2, 0.5); x.get(a, b); cout << "a=" << a << '\t' << "b=" << b << endl; char c; float d; GClass<char, float> y; y.set('m', 12.5); y.get(c, d); cout << "c=" << c << '\t' << "d=" << d << endl; } data1을 a에, data2를 b에 리턴하는 함수 a=2 b=0.5 c=m d=12.5
C++ 표준 템플릿 라이브러리, STL STL(Standard Template Library) STL의 구성 많은 제네릭 클래스와 제네릭 함수 포함 개발자는 이들을 이용하여 쉽게 응용 프로그램 작성 STL의 구성 컨테이너 – 템플릿 클래스 데이터를 담아두는 자료 구조를 표현한 클래스 리스트, 큐, 스택, 맵, 셋, 벡터 iterator – 컨테이너 원소에 대한 포인터 컨테이너의 원소들을 순회하면서 접근하기 위해 만들어진 컨테이너 원소 에 대한 포인터 알고리즘 – 템플릿 함수 컨테이너 원소에 대한 복사, 검색, 삭제, 정렬 등의 기능을 구현한 템플릿 함수 컨테이너의 멤버 함수 아님
STL과 관련된 헤더 파일과 이름 공간 헤더파일 이름 공간 컨테이너 클래스를 사용하기 위한 헤더 파일 해당 클래스가 선언된 헤더 파일 include 예) vector 클래스를 사용하려면 #include <vector> list 클래스를 사용하려면 #include <list> 알고리즘 함수를 사용하기 위한 헤더 파일 알고리즘 함수에 상관 없이 #include <algorithm> 이름 공간 STL이 선언된 이름 공간은 std
vector 컨테이너 동적 배열 !! 특징 가변 길이 배열을 구현한 제네릭 클래스 개발자가 벡터의 길이에 대한 고민할 필요 없음 원소의 저장, 삭제, 검색 등 다양한 멤버 함수 지원 벡터에 저장된 원소는 인덱스로 접근 가능 인덱스는 0부터 시작
vector 클래스의 주요 멤버와 연산자 size 1증가 pop_back() : 벡터의 끝에서 요소를 제거하고 벡터의 크기를 하나 감소
vector 다루기 사례
예제 10–9 vector 컨테이너 활용하기 #include <iostream> #include <vector> using namespace std; int main() { vector<int> v; // 정수만 삽입 가능한 벡터 생성 v.push_back(1); // 벡터에 정수 1 삽입 v.push_back(2); // 벡터에 정수 2 삽입 v.push_back(3); // 벡터에 정수 3 삽입 for(int i=0; i<v.size(); i++) // 벡터의 모든 원소 출력 cout << v[i] << " "; // v[i]는 벡터의 i 번째 원소 cout << endl; v[0] = 10; // 벡터의 첫 번째 원소를 10으로 변경 int n = v[2]; // n에 3이 저장 v.at(2) = 5; // 벡터의 3 번째 원소를 5로 변경 } 1 2 3 10 2 5
예제 10-10 문자열을 저장하는 벡터 만들기 연습 string 타입의 vector를 이용하여 문자열을 저장하는 벡터를 만들고, 5개의 이름을 입력 받아 사전에 서 가장 뒤에 나오는 이름을 출력하라 #include <iostream> #include <string> #include <vector> using namespace std; int main() { vector<string> sv; // 문자열 벡터 생성 string name; cout << "이름을 5개 입력하라" << endl; for(int i=0; i<5; i++) { // 한 줄에 한 개씩 5 개의 이름을 입력받는다. cout << i+1 << ">>"; getline(cin, name); sv.push_back(name); } name = sv.at(0); // 벡터의 첫 원소 for(int i=1; i<sv.size(); i++) { if(name < sv[i]) // sv[i]의 문자열이 name보다 사전에서 뒤에 나옴 name = sv[i]; // name을 sv[i]의 문자열로 변경 cout << "사전에서 가장 뒤에 나오는 이름은 " << name << endl; 이름을 5개 입력하라 1>>황기태 2>>한원선 3>>정원석 4>>이영희 5>>한홍진 사전에서 가장 뒤에 나오는 이름은 황기태
it는 원소가 int 타입인 벡터의 원소에 대한 포인터 iterator 사용 iterator란? 반복자라고도 부름, * 연산자, ++ 연산자 사용 가능 컨테이너의 원소를 가리키는 포인터 iterator 변수 선언 구체적인 컨테이너를 지정하여 반복자 변수 생성 vector<int>::iterator it; it = v.begin(); it는 원소가 int 타입인 벡터의 원소에 대한 포인터 vector<int> v; it ...... 1 2 3 4 5 4 9 v.begin() v.end()
예제 10-11 iterator를 사용하여 vector의 모든 원소에 2 곱하기 #include <iostream> #include <vector> using namespace std; int main() { vector<int> v; // 정수 벡터 생성 v.push_back(1); v.push_back(2); v.push_back(3); vector<int>::iterator it; // 벡터 v의 원소에 대한 포인터 it 선언 for(it=v.begin(); it != v.end(); it++) { // iterator를 이용하여 모든 원소 탐색 int n = *it; // it가 가리키는 원소 값 리턴 n = n*2; // 곱하기 2 *it = n; // it가 가리키는 원소에 값 쓰기 } for(it=v.begin(); it != v.end(); it++) // 벡터 v의 모든 원소 출력 cout << *it <<‘ ‘; cout << endl; 2 4 6
알고리즘 탐색(find): 컨테이너 안에서 특정한 자료를 찾는다. 정렬(sort): 자료들을 크기 순으로 정렬한다. 반전(reverse): 자료들의 순서를 역순으로 한다. 삭제(remove): 조건이 만족되는 자료를 삭제한다. 변환(transform): 컨테이너의 요소들을 사용자가 제공하 는 변환 함수에 따라서 변환한다.
STL 알고리즘 사용하기 알고리즘 함수 sort() 함수 사례 템플릿 함수 전역 함수 iterator와 함께 작동 두 개의 매개 변수 첫 번째 매개 변수 : 소팅을 시작한 원소의 주소 두 번째 매개 변수 : 소팅 범위의 마지막 원소 다음 주소 vector<int> v; ... sort(v.begin(), v.begin()+3); // v.begin()에서 v.begin()+2까지, 처음 3개 원소 정렬 sort(v.begin()+2, v.begin()+5); // 벡터의 3번째 원소에서 v.begin()+4까지, 3개 원소 정렬 sort(v.begin(), v.end()); // 벡터 전체 정렬
예제 10-12 sort() 함수를 이용한 vector 소팅 #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> v; // 정수 벡터 생성 cout << "5개의 정수를 입력하세요>> "; for(int i=0; i<5; i++) { int n; cin >> n; v.push_back(n); // 키보드에서 읽은 정수를 벡터에 삽입 } // v.begin()에서 v.end() 사이의 값을 오름차순으로 정렬 // sort() 함수의 실행 결과 벡터 v의 원소 순서가 변경됨 sort(v.begin(), v.end()); vector<int>::iterator it; // 벡터 내의 원소를 탐색하는 iterator 변수 선언 for(it=v.begin(); it != v.end(); it++) // 벡터 v의 모든 원소 출력 cout << *it <<' '; cout << endl; 주목 5개의 정수를 입력하세요>> 30 -7 250 6 120 -7 6 30 120 250
정렬(sort): 정수 배열(올림차순) #include <iostream> #include <algorithm> using namespace std; int main(){ int arr[] = {0, 4, 3, 1, 5}; sort(arr, arr + 5); for (int i = 0; i < 5; i++) cout << arr[i] << endl; return 0; } 1 3 4 5
정렬(sort): 정수 배열(내림차순) 5 #include <iostream> 4 #include <functional> #include <algorithm> using namespace std; int main(){ int arr[] = {0, 4, 3, 1, 5}; sort(arr, arr + 5, greater<int>() ); for (int i = 0; i < 5; i++) cout << arr[i] << endl; return 0; } 5 4 3 1
vector<char>의 정렬 #include <iostream> #include <vector> #include <algorithm> using namespace std; int main(){ vector<char> v; v.push_back('c'); v.push_back('b'); v.push_back('e'); v.push_back('a'); v.push_back('g'); sort(v.begin(), v.end()); for (int i = 0; i < 5; i++) cout << v[i] << endl; return 0; } a b c e g
vector: 사용자 정의 객체 정렬 (global < operator) 사용 22, MinJi #include <iostream> #include <vector> #include <algorithm> #include <string> using namespace std; class Person{ public: string name; int age; Person(string name, int age){ this->name = name; this->age = age; } }; bool operator <(const Person &a, const Person &b){ return a.age < b.age; } int main(){ vector<Person> v; v.push_back(Person("MinJi", 22)); v.push_back(Person("Kangho", 28)); v.push_back(Person("Minho", 26)); v.push_back(Person("Strange Yun", 25)); sort(v.begin(), v.end()); for (int i = 0; i < v.size(); i++) cout << v[i].age << ", " << v[i].name << endl; } 22, MinJi 25, Strange Yun 26, Minho 28, Kangho
vector: 사용자 정의 객체 정렬 (클래스내 연산자 오버로딩 ) 22, MinJi 25, Strange Yun #include <iostream> #include <vector> #include <algorithm> #include <string> using namespace std; class Person{ public: string name; int age; Person(string name, int age){ this->name = name; this->age = age; } bool operator <(const Person &a) const{ return this->age < a.age; } }; int main(){ vector<Person> v; v.push_back(Person("MinJi", 22)); v.push_back(Person("Kangho", 28)); v.push_back(Person("Minho", 26)); v.push_back(Person("Strange Yun", 25)); sort(v.begin(), v.end()); for (int i = 0; i < v.size(); i++) cout << v[i].age << ", " << v[i].name << endl; } 22, MinJi 25, Strange Yun 26, Minho 28, Kangho
vector: 사용자 정의 객체 정렬 (이름기준, 내림차순 ) 25, Strange Yun 22, MinJi 26, Minho #include <iostream> #include <vector> #include <algorithm> #include <string> using namespace std; class Person{ public: string name; int age; Person(string name, int age){ this->name = name; this->age = age; } }; bool cmp(const Person &a, const Person &b){ return a.name > b.name; } int main(){ vector<Person> v; v.push_back(Person("MinJi", 22)); v.push_back(Person("Kangho", 28)); v.push_back(Person("Minho", 26)); v.push_back(Person("Strange Yun", 25)); sort(v.begin(), v.end(), cmp); for (int i = 0; i < v.size(); i++) cout << v[i].age << ", " << v[i].name << endl; } 25, Strange Yun 22, MinJi 26, Minho 28, Kangho
데크의 경우, 전단과 후단에서 모두 요소를 추 가하고 삭제하는 것을 허용 데크(deque) 데크의 경우, 전단과 후단에서 모두 요소를 추 가하고 삭제하는 것을 허용
리스트(list) 외부에서 보면 벡터와 동일 이중 연결 리스트로 구현
집합(set) 수학적인 집합과 비슷 집합(set)은 동일한 키를 중복해서 가질 수 없다. (예) A = { 1, 2, 3, 4, 5 }는 집합이지만 B = { 1, 1, 2, 2, 3 }은 집합이 아니다.
맵(map) Map은 사전과 같은 자료 구조 키(key)가 제시되면 Map은 값(value)을 반환한다
예제
실행 결과
스택(stack) 스택은 늦게 들어온 데이터들이 먼저 나가는 자료 구조
큐(queue)는 먼저 들어온 데이터들이 먼저 나 가는 자료 구조
실습문제 1. template 함수 작성하기 배열을 받아 가장 큰 값을 반환하는 제네릭 함 수 biggest()를 작성하라. int main() { int x[] = {1, 10, 100, 5, 4}; cout << biggest(x, 5) << endl; // 5는 배열 x의 크기 double y[] = {6.4, 3.3, -200.6, 7.7, 8.8, 20.3}; cout << biggest(y, 6); // 6는 배열 y의 크기 }
실습문제 7. 다음 프로그램은 컴파일 오류가 발생한다. 왜 컴파일 오류가 발생하나? #include <iostream> using namespace std; class Circle { int radius; public: Circle(int radius=1) { this->radius = radius; } int getRadius() { return radius;} }; template <class T> T bigger(T a, T b) { // 두 개의 매개 변수를 비교하여 큰 값을 리턴 if(a > b) return a; else return b; } 컴파일 오류
실습문제 7. 계속 int main() { int a=20, b=50, c; c = bigger(a, b); cout << "20과 50중 큰 값은 " << c << endl; Circle waffle(10), pizza(20), y; y = bigger(waffle, pizza); cout << "waffle과 pizza 중 큰 것의 반지름은 " << y.getRadius() << endl; } p. 474참조 Note. bigger() 함수를 중복하여 문제를 해결하시오. 반지름값이 큰 Circle 객체를 반환하도록 추가할 것.
실습문제 7-2 문제 7에 대한 해결을 다른 방법으로 생각해보 자. bigger() 함수에서 if(a > b) return a; 위 문장이 정상적으로 동작하기 위해서는 Circle 클래스에 연산자 “>”이 반지름 값이 큰 값이면 true를 반환하게 중복 정의되어야 한다. bool operator > (Circle op2)