C++ 프로그래밍

송종빈·2023년 12월 17일
0

생성자와 접근제어

생성자

생성자: 초기화를 담당하는 함수

  • 객체의 생성과 동시에 초기화
  • 생성자 중복 정의 가능
  • 반환값 없음
  • 초기화 대상: 멤버 변수, 메모리 공간, 기타 자원들

생성자 호출 방법
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): 외부에서 안전하게 멤버변수를 변경할 수 있도록 하는 함수

객체와 함수의 관계

  1. 객체가 함수의 매개변수로 전달됨
    • ex) void makeDouble(Pizza p) {p.size += 2;}
  1. 객체의 참조자가 함수의 매개변수로 전달됨
    • ex) void makeDouble(Pizza& p) {p.size += 2;}
  1. 함수가 객체를 반환
    • 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;
}

C++ 표준 템플릿 라이브러리 (STL)

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번째 요소 삭제

STL 알고리즘 사용

알고리즘 함수: 템플릿 함수 / 전역 함수 / iterator와 함께 작동

  • STL 컨테이너 클래스의 멤버함수가 아님!

sort() 함수 사례
sort(v.begin(), v.begin()+3); // v.begin()에서 처음 3개 원소 정렬

array 클래스

  • 벡터는 생성/소멸을 하는데 많은 시간이 소요됨 (정적의 특성)
  • 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()

this 포인터

현재 객체를 참조하는 포인터 (=객체 자신 포인터)

  • 클래스의 멤버함수 내에서만 사용
  • 컴파일러가 선언한 변수 (개발자가 선언 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 객체를 가리키는 포인터를 정의하면 이 포인터로 호출할 수 있는 함수는 const 함수 뿐임

복사 생성자와 정적 멤버




연산자 오버로딩과 프렌즈


상속







다형성과 가상함수












파일처리





profile
Student Dev - Language Tech & Machine Learning

0개의 댓글