- C와 C++ 차이
- C : 절차지향 / C++ : 객체지향(클래스 기반 문법들 많이 제공)
- 클래스 = 틀 = 자료형(int, float, double)
- 즉, 클래스란 객체(Object) 사용자 정의 자료형
- 클래스: 붕어빵 틀
- 객체: 붕어빵
- 즉, 클래스란 객체(Object) 사용자 정의 자료형
- 게임이란?
- 객체들간의 상호 작용을 화면에 보여주는 것 (카트라이더에서 카트 class 객체들)
- C++ 쓰는 이유 중 하나 : 성능
- 성능: 속도 / 메모리
- 속도 : 비슷함
- 메모리 : 메모리 공간을 효율적으로 사용(낭비가 적음)
- 게임 설치할 때 메모리 부족하다고 뜨면 어차피 게임이 안 깔리니까 못함. 설치한 후 게임 도중 메모리가 부족하다고 뜨면 크래시 남. 메모리가 동적으로 변동됨. 동적으로 생성/해제 빈번
- 시간 복잡도(실행 시간), 공간 복잡도(메모리 공간)
- 성능: 속도 / 메모리
- 생성자(Constructor)
- 객체가 생성될 때 필드나 여러 절차들을 초기화하는 함수
- 접근 제어자가 반드시 public으로 선언되어야 한다.
- return 타입이 없다. 즉, 반환값이 없다.
- 오버로딩(Overloading)을 통해 중복정의가 가능하다.
- 객체가 생성될 때 자동으로 생김
- 디폴트 생성자(Default Constructor)
- 매개변수가 없거나 초기화된 매개변수(defalut parameter)를 가진 생성자
- default 생성자의 문제
- 기본값으로만 초기화 해줌
class Test { int score; public: Test() {} // default constructor }
- 초기화 리스트(Initialization List)
- 생성자에서 필드를 간단하게 초기화하는 방법
class Test { int score; public: Test(int s = 10) : score(s) {} }
- 생성자에서 필드를 간단하게 초기화하는 방법
- 초기화 리스트 사용 이유?
- 필드에 const로 선언된 변수(상수)를 초기화하는 경우
- 필드에 선언된 레퍼런스 변수를 초기화하는 경우
- 이 두가지 경우 모두 생성과 동시에 초기화되어야하는 변수들이기 때문에 초기화 리스트에 넣어야 함
- { } 이 안은 생성이 된 이후라서 안됨
- 소멸자(Destructor)
- 소멸자는 객체가 소멸될 때 자동으로 실행되는 클래스의 멤버 함수
- 생성자는 클래스의 초기화를 돕도록 설계됐지만 소멸자는 청소를 돕도록 설계됨
- 소멸자 이름은 클래스 이름과 같아야 하고 앞에 ~를 달아야 한다.
- 소멸자는 인수가 없다.
- 소멸자는 반환 값이 없다.
- 참조(Reference)
- 사용 이유?
- 레퍼런스 변수를 사용하는 이유는 메모리를 절약하기 위해서. 레퍼런스 변수로 선언하면 따로 메모리를 잡지 않고 해당 변수에 접근할 수 있기 때문에 쓸데없는 메모리를 잡지 않게됨
- 레퍼런스 변수는 변수 메모리 자체가 따로 잡히는 것이 아니라 값을 담고있지는 않음
- 별명이 하나 생기는 것
- int&num1 = num2; 라고 하는순간 num2에 해당하는 메모리 공간에 num1이라는 이름을 하나 더 붙여주는 것
- 사용 이유?
- 생성, 소멸자 왜 쓰나?
- Memory Leak 최소화 하기 위해. 성능적으로 놓치는 것 없게 하기 위해
- RAII : 리소스의 수명은 생성/소멸자로 결정된다 (면접질문가능)
- 개체의 생성, 소멸은 프로그래머가 직접 관리해야 한다
- 복사 대입 연산자
- 같은 타입의 객체를 이미 생성되어 있는 객체에 값을 복사할 때 사용
- 메모리 구조
- 힙 영역 : Only 동적 할당으로 만든 변수들만 쌓임.
- 왜 써? 스택이 작으니까. 스택은 비워놓는 게 좋음. 공간 작음
- 전역변수 쓰면 되잖아?
- 전역변수 단점: 프로그램 끝날 때까지 메모리 잡혀 있음
- 잘 안쓰고 메모리 낭비
- 전역변수 단점: 프로그램 끝날 때까지 메모리 잡혀 있음
- 동적할당으로 만든 변수들 특징: 이름이 없음. 메모리 할당 후 주소값을 리턴해줌.
- 주소값 보관 변수 = pointer
- int* ptr= new int; //여기서 new는 함수임
- 프로그래머가 요청할 때만 할당이 됨
- 공간도 스택보다 큼
- 힙 영역 : Only 동적 할당으로 만든 변수들만 쌓임.
- 포인터(pointer)
- 메모리의 주소를 가지고 있는 변수
- 주소 값을 통한 메모리 접근을 한다(간접 참조)
- 포인터 변수는 다 4 byte!!!!
- 왜 써?
- 예를 들어 Animal이라는 클래스에 지역변수로 스택에 30 byte를 쓴다고 가정하자.
- 근데 포인터 변수는 4 byte라고 했지.
- Animal * ptr (4 byte) = new Animal (30 byte)
- 다 묶어서 포인터변수로 부르면 4byte로 메모리 save
- 쓰는 이유 하나 더! 포인터는 이름 없는 애 가리킬 수 있어. 주소로!
- null ptr은 가리키는 게 없음. 값이 들어가야 화살표가 생기는 거니까
포인터 변수는 4byte 잡아 먹음. 근데 Reference 변수는 그것 조차 안하겠다는 것임
- 레퍼런스(reference)
- 레퍼런스 = 참조자 (C++ 문법)
- 참조자는 자신이 참조하는 변수를 대신할 수 있는 또 하나의 이름이다.
- 즉, 변수에 별명(별칭)을 하나 붙여주는 것
- 변수 명을 통해서 메모리를 참조한다. (직접 참조)
-
- 참조 대상 변경 불가
예를 들어 포인터 같은 경우에는 덮어씌우기 가능.
그리고 선언과 동시에 초기화 안해줘도 됨.
<포인터>
<참조>
한번 정해주면 다른 별명으로 못 바꿈.
그래서 생성과 동시에 초기화.
int & num; (X) 별명 대상이 있어야 함.
num과 ref 같은 경우 대상 한번 정해지면 한몸. ref==num임.
그래서 ref가 num2의 별명이 되는게 아니라 (ref는 위에서 num의 별명으로 갔으니까)
대입이 되어 버리는 것임.
그렇다면 참조의 한계는?
선언과 동시에 초기화 해야 한다는 것
* call by value :
Swap(int a, int b) 여기에서 메모리를 따로 잡기 때문에 지역변수 값(int a, int b)만 바뀌고 실제 값이 안바뀌는 것임.
참조는 메모리를 따로 안잡고 main에 직접 들어간 거라서 값이 바뀜.
- 복사 생성자
- 객체를 인자로 넣을 때 복사생성자가 불린다
- 자동 복사 생성자의 문제점?
- 단순히 대입만 하기 때문에 포인터가 있을 경우 주소 값만 바꿔준다는 문제가 있음 (얕은복사 문제)
- 함수들은 메모리에 없음
- 변수에 접근하려면 1)이름이 있거나 2)주소가 있어야 함
- 동적 할당 하는 이름이 없어서 포인터로 접근함
답은 10, 10 이 나옴.
cout 까지 출력된 이후
return 이후에 지역변수인 a, b가 소멸될 때가 문제인데,
생성 순서와 반대로 소멸됨(스택 구조 참고)
~CMyData b(a)
~CMyData a(10)
순서로 소멸되는데 ~CMyData b(a) 과정에서
b의 복사 생성자인 a가 불리는데
이때 위의 코드에서는 따로 복사생성자를 생성하지 않았기 때문에
자동으로 복사생성자가 불리는데 이 복사생성자는 단순히 a의 값을 복사(대입)만 하는 형태임.
이 때 포인터도 그대로 대입하게 되는데 같은 포인터를 가리키게 되고
메모리 해제 할 때 ~CMyData b(a)가 가리키는 포인터를 해제했고
~CMyData a(10)에서 메모리 해제하려 했더니 헤제할 메모리가 없는 상황이 발생
- 얕은 복사, 깊은 복사 (시험 많이 나옴)
- 복사생성자는 얕은 복사에서는 crash가 나기 때문에 복사 생성자에서는 깊은 복사를 해야 함
- const는 원본 안바꾸기 위해서 붙여주고 &가 없으면 무조건 메모리를 잡기 때문에 무한으로 객체를 부를 수 있음.
- 생성자가 뭘 부를지는 ( 괄호 안에서 결정하는데,
- b(a 의 경우 a를 부르는 중에 a도 animal 부르고... 무한 반복! -> Crash!
위 긴 코드의 문제는 얕은복사가 아니라(얕은복사가 무조건 나쁜게 아님)
바로 위의 복사 생성자를 따로 생성해주지 않아서 문제가 생기는 것임.
위 코드 처럼 복사 생성자를 만들 때 메모리를 새로 할당 해주고, 포인터가 가리키는 위치에 값을 복사해줘야 함!
'C++' 카테고리의 다른 글
[C++] 개체지향 프로그래밍 / OOP, 접근 제어자, 스택/힙, new/delete (0) | 2022.02.05 |
---|---|
#2. 복사 생성자의 호출 시점 (0) | 2022.02.04 |
[C++] 참조(Reference) (0) | 2022.01.22 |
[C++] Bool 데이터형 (0) | 2022.01.21 |
[C++] 입력(Input) (0) | 2022.01.21 |
댓글