생성자: 초기화를 담당하는 함수
- 객체의 생성과 동시에 초기화
- 생성자 중복 정의 가능
- 반환값 없음
- 초기화 대상: 멤버 변수, 메모리 공간, 기타 자원들
생성자 호출 방법
1. Time a; // 오류, 초기화값 없음
2. Time b(10,25); // OK, but 예전 방법
3. Time c = {10,25}; // OK, but 간결하지 않음
4. Time d{10,25}; // OK, 최선의 방법
디폴트 생성자
- 인수가 없는 생성자
- 객체를 생성할때 인수를 주지 않으면 자동으로 호출
멤버 초기화 리스트
1. Time(int h, int m) : hour{h}, minute{m}
2. Time(int h, int m) : hour(h), minute(m)
3. Time(int h=0, int m=0) : hour{h}, minute{m}
소멸자: 객체가 소멸될때 호출되는 특정한 멤버 함수
- 객체의 소멸: 생성된 객체가 범위를 벗어나면 객체는 소멸됨
- 객체가 할당받은 동적메모리를 해제해야할때 사용
- 사용 방법: ~(클래스 이름)
- 반환값 없음
- 매개변수 사용 불가
- 파일의 종료, 메모리 반환 등 프로그램을 종료하기 전에 자원을 반환하는데 사용
기말고사 범위 시작
접근제어: 외부에서 특정한 멤버 변수나 멤버 함수에 접근을 제어하는 것
- 접근자 (getter): private으로 선언된 멤버변수를 읽어서 외부로 전달
- 설정자 (setter): 외부에서 안전하게 멤버변수를 변경할 수 있도록 하는 함수
- 객체가 함수의 매개변수로 전달됨
- ex)
void makeDouble(Pizza p) {p.size += 2;}
- 객체의 참조자가 함수의 매개변수로 전달됨
- ex)
void makeDouble(Pizza& p) {p.size += 2;}
- 함수가 객체를 반환
- ex)
Pizza createPizza() {Pizza p(10); return p;}
- 함수가 객체를 반환할 때도 객체의 내용이 복사될뿐 원본이 전달되지 않음
일반화 (제네릭; generic): 함수나 클래스를 일반화시키고, 매개변수 타입을 지정하여 틀에서 찍어내듯이 함수나 클래스 코드를 생산하는 기법
템플릿: 함수나 클래스를 일반화하는 C++ 도구
- template 키워드로 함수나 클래스 선언
- 변수나 매개변수 타입만 다르고, 코드 부분이 동일한 함수를 일반화시킴
제네릭 타입: 일반화를 위한 데이터 타입
ex)
template <class T> void myswap (T& a, T& b) { T tmp; tmp = a; a = b; b = tmp; }
STL (Standard Template Library)
- 표준 템플릿 라이브러리 (C++ 표준 라이브러리 중 하나)
- 많은 제네릭 클래스와 제네릭 함수 포함
- 컨테이너 & iterator & 알고리즘
- 컨테이너 (템플릿 클래스): 자료구조를 표현한 클래스 (리스트, 큐, 스택, 맵, 셋, 벡터)
- iterator: 컨테이너의 원소들을 순회하면서 접근하기 위해 만들어진 컨테이너 원소에 대한 포인터
- 알고리즘 (템플릿 함수): 컨테이너 원소에 대한 복사, 검색, 삭제, 정렬 등의 기능을 구현한 템플릿 함수 (컨테이너의 멤버함수 아님!)
STL 컨테이너의 종류
컨테이너 클래스 설명 헤더 파일 vector 가변크기의 배열을 일반화하는 클래스 vector deque 앞뒤 모두 입력 가능한 큐 클래스 deque list 빠른 삽입/삭제 가능한 리스트 클래스 list set 정렬된 순서로 값을 저장하는 집합 클래스, 값은 유일 set map (key, value) 쌍을 저장하는 맵 클래스 map stack 스택을 일반화한 클래스 stack queue 큐를 일반화한 클래스 queue
STL iterator의 종류
iterator의 종류 iterator에 ++ 연산 후 방향 read/write iterator 다음 원소로 전진 read/write const_iterator 다음 원소로 전진 read reverse_iterator 지난 원소로 후진 read/write const_reverse_iterator 지난 원소로 후진 read
클래스이름 배열이름 [배열_크기];
ex)
Circle objArray[10] = { Circle(100, 100, 30), Circle(100, 200, 50), Circle(100, 300, 80) };
벡터: 동적 배열 (<-> 기존의 정적 배열 array는 기존 배열에 요소 추가 / 중간 요소 삭제 등 데이터 처리에 어려움이 있음)
- 컴파일 시간에 배열의 크기를 미리 결정할 필요 없음
- 필요할때마다 메모리 할당
- 프로그램의 속도 ↓
- 템플릿으로 설계됨
- 어떤 자료형이든 가능 (but {1, 2, 'c', 7.5} 같은 형태는 불가능)
- 요소의 증감에 따라 자동으로 크기 조절 (=동적)
- 배열의 특징을 지님 (but 배열과 달리 메모리상에서 반드시 연속적이지는 않을 수 있음)
주요 멤버 & 연산자
| 멤버 & 연산자 함수 |
| ----- |
| push_back(element) |
| pop_back() |
| at(int index) |
| begin() |
| end() |
| empty() |
| erase(iterator it) |
| insert (iterator it, element) |
| size() |
ex)
#include <vector> using namespace std; int main(void) { vector<int> fibonacci {0,1,1,2,3,5,8,13}; for (auto& number: fibonacci) {cout << number << '';} return 0; }
ex)
벡터에서 요소의 위치는 반복자 (iterator)을 이용하여 표시
- begin: 첫번째 요소의 주소
- end: 마지막 요소 '다음'의, 벡터가 끝났음을 알려주는 특수한 노드(null)의 주소! (안에 data 없음)
ex)
for (auto p = v.begin(); p != v.end(); ++p) {cout << *p << endl;}
ex) 벡터의 중간에서 삭제
v.erase(v.begin() + i); // i번째 요소 삭제
알고리즘 함수: 템플릿 함수 / 전역 함수 / iterator와 함께 작동
- STL 컨테이너 클래스의 멤버함수가 아님!
sort() 함수 사례
sort(v.begin(), v.begin()+3); // v.begin()
에서 처음 3개 원소 정렬
- 벡터는 생성/소멸을 하는데 많은 시간이 소요됨 (정적의 특성)
- std::array 클래스를 사용하면 벡터의 장점 + 기존 배열의 성능을 동시에 누릴 수 있음
ex)
#include <array> using namespace std; int main() { array<int, 3> list{1,2,3}; for (int i = 0; i < list.size(); ++i) {++list[i];} for (auto& elem: list) {cout << elem << "";} return 0; }
포인터: 주소를 가지고 있는 변수 (메모리의 주소가 저장되어있음)
주소 연산자 (&)
- 포인터 p에 변수의 '주소'를 저장
int number = 10; int *p; p = &number; // 변수 number의 주소를 포인터 p에 저장
간접 참조 연산자 (*)
- 포인터 p가 가리키는 메모리 공간의 '값'을 읽어오거나 변경
nullptr
포인터가 빈 것은 NULL이 아니라 nullptr을 사용하여야함
동적 메모리 할당: 프로그램이 실행 도중에 동적으로 메모리를 할당 받음
<-> 정적 할당: 변수 선언을 통해 필요한 메모리 할당 (많은 양의 메모리는 배열 선언을 통해 할당)
- 필요한 양이 예측되지 않는 경우 사용
- 힙(heap) 메모리에서 할당
new 연산자
- 기본 타입 메모리 할당, 배열 할당, 객체 할당, 객체 배열 할당
- 객체의 동적 생성 - 힙 메모리로부터 객체를 위한 메모리 할당 요청
- 객체 할당 시 생성자 호출
delete 연산자
- new로 할당받은 메모리 반환
- 객체의 동적 소멸 - 소멸자 호출 뒤 객체를 힙 메모리에 반환
delete 사용시 주의사항
(1) 동적으로 할당받지 않는 메모리 반환 - 오류
(2) 동일한 메모리 두번 반환 - 오류
(3) delete 시 []의 잘못된 사용 - 오류는 아니지만 비정상적 반환
스마트포인터: 프로그래머가 동적메모리 할당 후 잊어버려도 자동으로 동적 메모리 삭제
- 스마트포인터는 자동으로 nullptr로 초기화
- 정적으로 할당된 것은 스마트포인터로 가리킬 수 없음
- 손으로 delete 직접 해주면 delete를 두번해주는거라 안됨
#include<memory>
는 안써도 되지만 원칙적으로는 쓰는게 맞음ex)
#include <memory> using namespace std; int main() { unique_ptr<int> p(new int); // 기존방식: p(int) ~ new가 없었음 *p = 99; // 이후 닫는 괄호 '}' 만나면 p가 삭제되면서 동적메모리도 삭제 }
ex2)
#include <memory> using namespace std; int main() { unique_ptr<int[]> buf(new int[10]); // 여기서 buf는 배열의 이름이 아닌 스마트포인터의 변수명 (배열명은 따로 없음!) }
- 동적으로 생성된 객체의 멤버에 접근하려면 도트 연산자(.) 사용
- ex)
(*pDog).getAge()
- 위의 표기법이 번거로우므로 this 연산자 (->) 사용
- ex2)
pDog -> getAge()
현재 객체를 참조하는 포인터 (=객체 자신 포인터)
- 클래스의 멤버함수 내에서만 사용
- 컴파일러가 선언한 변수 (개발자가 선언 x)
this가 필요한 경우
(1) 매개변수의 이름과 멤버변수의 이름이 같은 경우
(2) 멤버함수가 객체 자신의 주소를 리턴할때ex)
class Sample { public: Sample* f() { return this; } };
this의 제약사항
(1) 멤버함수가 아닌 함수에서 this 사용 불가 (why? 객체와의 관련성이 없음)
(2) static 멤버함수에서 this 사용 불가 (why? 객체가 생기기전에 static 함수 호출이 있을 수 있기 때문)
const 포인터
- 멤버함수를 const로 정의하면 함수 안에서 멤버변수를 변경하는 것이 금지됨
- const 객체를 가리키는 포인터를 정의하면 이 포인터로 호출할 수 있는 함수는 const 함수 뿐임