수료가 2달 조금 넘게 남았다.
팀 프로젝트를 마치고 남은 기간동안 direct X 수업과 개인 포폴진행을 병행한다고 한다.
나중에 공부 하고 싶었던 거지만 Direct X는 알아두면 좋다는 얘기는 들었었고, C++의 중요성은 이미 알고 있었지만 두 달이라는 짧은 시간안에 얼마나 배울 수 있을지는 모르겠다..
그래도 수업을 진행하는거니 복습 겸 정리해서 올리려고 한다.
C++의 클래스 , 접근 지정자
#include <iostream>
using namespace std;
class Animal
{
private:
const int MaxAge = 10;
int Age = 0;
protected:
public:
};
클래스의 틀은 C#과 크게 다른점은 없는 것 같다.
다만 C#에선 접근지정자를 변수 명 앞에 써주었다면 (ex. public int a = 0;)
C++에선 위와같이 표현 한다.
만약 아무것도 안적어 둔다면 Private이다.
그리고 C#에 비해 const를 많이 쓴다고 한다.(상수로 만드는)
Animal이란 클래스를 만들고, 그 안에 값이 10인 상수 MaxAge와 Age라는 변수를 선언 해주었다.
생성자와 생성자 이니셜라이즈
상수는 말 그대로 상수이기 때문에 일반적으로는 변경이 안 되지만, 생성할때 1번의 기회가 주어진다.
바로 생성자 이니셜라이즈
#include <iostream>
using namespace std;
class Animal
{
private:
const int MaxAge = 10;
int Age = 0;
protected:
public:
//생성자
Animal(int max) : MaxAge(max), Age(1) // 생성자 이니셜라이즈(가장 먼저 호출 됨)
{
//상수기 때문에 이건 안된다.
//MaxAge = max;
}
void YourAge()
{
cout << "MaxAge는 : " << MaxAge << endl;
cout << "Age는 : " << Age << endl;
}
};
생성자 뒤에 ' : ' 를 붙이고 위 코드와 같이 상수를 입력받은 max로 초기화하고, Age는 1로 초기화 해주었다.
아래 주석으로 처리해놓은 코드 MaxAge = max 는 MaxAge가 상수라서 되지 않지만, Age와 같은 변수라면 가능하다.
하지만 생성자 이니셜라이즈는 가장 먼저 호출되고 빠르기 때문에 꼭 상수가 아니라 일반 변수라도 이용 할 수 있다.
확인하기 위한 YourAge 함수를 만들어 주었다.
int main()
{
Animal anim(5);
anim.YourAge();
}
위와 같이 생성해주고 만든 함수를 실행 시켜주면 , 아래와 같이 잘 뜨는것을 볼 수 있다.
소멸자
//소멸자
~Animal() //종료 될 때 (해당클래스가 사라질때)
{
cout << "나 소멸 됨ㅠ" << endl;
}
C++클래스의 소멸자는 앞에 ~를 붙여주어 만들면 된다.
아래와 같이 마지막 코드가 끝나고 끝이 날 때 뜨는것을 볼 수 있다.
Stack 정적 할당과 Heap 동적 할당
프로그래밍을 공부 해보신 분이라면 StackOverFlow 라는 단어를 어디선가 보셨을 것이다.(유명한 사이트도 있다)
stack 영역 메모리가 부족하면 뱉어내는 에러 메세지인데..
Stack영역은 상대적으로 크기가 작고 컴파일 타임에 크기가 결정되기 때문에,
우리는 비교적 공간이 크고 런타임때 크기가 정해지는 Heap 영역에 동적을 할당하는 방법을 생각 할 수 있다.
(다만 포인터로 메모리 영역을 접근해야 하기 때문에 데이터를 읽고 쓰는게 느리다고 한다)
int main()
{
Animal anim(5);
anim.YourMaxAge();
anim.HowOld();
}
위 코드처럼 생성하면 stack 정적 할당이다.
스택 메모리 데이터는 함수 영역을 벗어나면 자동으로 소멸되기 때문에, 메모리 해제가 따로 필요없다.
' . ' 연산자를 통해 인스턴스 접근이 가능하다.
int main()
{
Animal* anim = new Animal(5); // heap에 생기는건 뉴 라는 키워드. 동적할당
//(*anim).HowOld();
anim->YourMaxAge();
anim->HowOld();
delete anim; // 변수가 가르키고 있는 인스턴스를 삭제
}
위 코드는 New라는 키워드를 사용하여 Heap에 동적할당을 해주는 코드이다.
Animal 클래스가 *anim 포인터에 할당된 걸 알 수 있다.
포인터의 가장 큰 목적은 런 타임에 이름 없는 메모리를 할당받아 포인터에 할당하여, 할당받은 메모리에 접근하는 것이다.
포인터로 안의 인스턴스에 접근하는 방법은 아래와 같다.
anim->Howold(); == (*anim).HowOld();
둘 다 같은 표현이지만, 전자가 훨씬 편하다.
*anim 포인터는 Stack영역에 생성되어 Heap에 생성된 새로운 인스턴스를 가리킨다.
가비지 컬렉터가 해결해주는 C#과는 다르게 마지막에 delete로 메모리를 해제 해주어야한다.
(delete는 소멸자를 호출한다.)
해제를 해주지 않으면 메모리 누수가 발생한다.
New - Delete는 C언어에서 자주 쓰이는 malloc - free와 비슷하다.
암시적으로 생성되는 것들
생성자,소멸자,복사 생성자, 대입연산자는 우리가 정의 하지 않아도 생성된다.
생성자 , 소멸자는 위에서 확인을 했고, 복사 생성자부터 알아보자.
int main()
{
Animal* anim = new Animal(5);
Animal* anim2 = new Animal(*anim); // 복사 생성자 자동으로 생성됨.
anim->YourMaxAge();
anim->HowOld();
anim2->YourMaxAge();
anim2->HowOld();
cout << "anim의 주소 : " << anim << endl;
cout << "anim2의 주소 : " << anim2 << endl;
delete anim;
delete anim2;
}
만들어놓은 anim을 그대로 anim2에 넣어주었다.
따로 정의하지 않아도 가능하다.
할당할때 따로 값을 입력해주지 않았음에도 불구하고, 값이 같은것을 볼 수 있다.
하지만 두 포인터가 가리키는 주소는 다르다.
하지만 대입 연산자에 주의점이 있다.
복사에는 얕은 복사와 깊은 복사가 있는데, 따로 정의해주지 않는다면 얕은 복사가 일어난다.
실험을 위해 코드를 작성했다.
class Animal
{
private:
const int MaxAge = 10;
int Age = 0;
int* P = nullptr;
protected:
public:
//생성자
Animal(int max) : MaxAge(max), Age(1) // 생성자 이니셜라이즈(가장 먼저 호출 됨)
{
//멤버변수 P생성
P = new int(10);
}
//소멸자
~Animal() //종료 될 때 (해당클래스가 사라질때)
{
cout << "나 소멸 됨ㅠ" << endl;
delete P;
}
}
1. private에 int형 포인터 p를 선언해주었다.
2. 생성자에서 힙에 10이라는 값을 동적 할당 해주었다.
3. 소멸자에서 P의 메모리 할당을 해제 해주었다.
그리고 아까 복사 생성자를 실험해본 코드 그대로 실행해보자.
오류가 난다.
오류의 이유는 따로 복사 생성자의 정의를 해주지 않았기 때문에 얕은 복사가 일어났다.
anim에서의 포인터 P는 동적 할당한 10이라는 값을 가리키고 있다.
anim2를 할당할때, 얕은 복사가 일어나면서 anim2의 포인터 P도 anim과 같은 값을 가리키고 있다.
delete로 anim의 메모리 할당을 해제 해주면서 소멸자에 적어놓은 P의 메모리 할당도 해제 되는데,
그러면 anim2의 포인터 P는 더 이상 가리킬 곳이 없어져서 에러가 난것이다.
이 에러를 없애기 위해 , 복사생성자를 정의 해주자.
//복사 생성자 - 깊은 복사 //const는 복사 하려는 대상의 값이 바뀌지 않게 상수화를 함
Animal(const Animal &ref) : MaxAge(ref.MaxAge)
{
Age = ref.Age;
P = new int(*ref.P);
}
복사하려는 대상의 값이 바뀌면 안되기 때문에 const로 Animal형 레퍼런스 타입의 ref를 매개변수로 받는다.
생성자 이니셜라이즈로 ref의 MaxAge를 초기화 시켜주고,
Age는 ref의 age, P는 ref의 P의 값을 그대로 가져와서 새로 할당 해준다.
이러면 깊은 복사가 일어나며 더 이상 에러가 나지 않는다.
대입연산자와 산술 연산자?
void operator = (const Animal& ref)
{
Age = ref.Age;
P = new int(*ref.P);
}
Animal operator + (const Animal& ref)
{
Animal anim(MaxAge);
anim.Age = Age + ref.Age;
return anim;
}
int main()
{
Animal* anim = new Animal(5);
Animal* anim2 = new Animal(*anim); // 복사 생성자 자동으로 생성됨.
Animal anim3(7);
anim3 = *anim + *anim2;
anim3.HowOld();
delete anim;
delete anim2;
}
위와 같이 대입 연산자와 산술 연산자라고 하는지 모르겠으나 +도 입맛대로 만들어 줄 수 있다.
복사 생성 소멸이 계속 일어나며 anim3에 anim과 anim2가 더해져서 age가 2가 된것을 볼 수 있다.
함수에서의 Const , Static 사용
//앞에 const int가 붙으면 리턴되는 값을 상수화 해서 리턴함
const int HowOld()
{
cout << endl<< "Age는 : " << Age << endl << endl;
return Age;
}
함수 앞에 Const 를 붙이면 return하는 값을 상수화 시켜서 리턴한다.
const int HowOld() const //뒤에 const를 붙이면 멤버 변수의 값을 바꿀 수 없다.
{
//Age = 4; 불가능
cout << endl<< "Age는 : " << Age << endl << endl;
return Age;
}
함수 뒤에 const를 붙이면,
멤버 변수의 값을 바꿀 수 없다.
void YourMaxAge()
{
static int Count = 0;
cout << "MaxAge는 : " << MaxAge << "Count는 :" << Count++ << endl;
}
이런식으로 클래스 함수안에 Static 을 사용하면 이 클래스로 생성되는 모든 인스턴스들이 메모리 Data영역에 생성된 Count라는 int형 static 변수를 공유한다.
int main()
{
Animal* anim = new Animal(5);
Animal* anim2 = new Animal(*anim); // 복사 생성자 자동으로 생성됨.
Animal anim3(7);
//anim3 = *anim + *anim2;
anim->YourMaxAge();
anim2->YourMaxAge();
anim3.YourMaxAge();
delete anim;
delete anim2;
}
위 코드같이 입력하고, 위에 만들어둔 함수를 호출하면..
위와 같이 공유한 Count가 올라가는것을 볼 수있다.
함수 외에서 접근하는 방법은 없다.
1일차 수업을 마치며
많은 사람들이 C++을 raw하고 rough하다고 얘기한다.
프로그래밍의 꽃이라고 불리는 포인터도 있고 나중에라도 언리얼을 만져보고 싶은 마음에 C#보다 C++을 더 배우고 싶었고 잘하고 싶었다.
그냥 웃기게 얘기하자면 뭔가 낭만이 있는 언어라고 생각했다.
그런데 수업 완전 초기에 C++을 잠시 한 적이 있었는데 너무 절망적이였다.
완전 처음 배우고 로또번호 6개 뽑기도 어려운데 포인터와 레퍼런스.. 링크드 리스트를 했는데 이해가 되는 부분이 하나도 없었다.
지금은 자료구조와 C#을 조금 하다 와서인지 복습을 하면 50% 이상은 이해가 되는거 같지만 그래도 어렵다.
더 많이 노력을 해야겠다.
강사님의 강의와 인터넷 자료들을 참고하여 만들었는데 틀린 부분이 있다면 지적 해주시면 감사하겠습니다.
'프로그래밍 공부 > C++ 프로그래밍' 카테고리의 다른 글
Direct X 4일차💻 <WINAPI> #2 (0) | 2022.06.19 |
---|---|
WINAPI 추가정리 (0) | 2022.06.19 |
Direct X 3일차💻 <WINAPI> #1 (0) | 2022.06.19 |
Direct X 2일차💻 C++의 동적 배열 (0) | 2022.06.15 |
Direct X 수업 2일차💻 스마트 포인터 (0) | 2022.06.15 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!