├── .DS_Store ├── .gitattributes ├── 000 └── README.md ├── 001 └── README.md ├── 002 └── README.md ├── 003 └── README.md ├── 004 └── README.md ├── 005 └── README.md ├── 006 └── README.md ├── 007 └── README.md ├── 008 └── README.md ├── 009 ├── Array10.cpp ├── Array10.h ├── Dot.cpp ├── Dot.h ├── Location.cpp ├── Location.h ├── README.md ├── main.cpp └── main2.cpp ├── 010 ├── Game_Information.cpp ├── Game_Information.h ├── README.md ├── main.cpp └── sum.cpp ├── 011 ├── Game_Information.cpp ├── Game_Information.h ├── README.md └── main.cpp ├── 012 ├── Dot.cpp ├── Dot.h ├── Location.cpp ├── Location.h ├── README.md └── main.cpp ├── 013 ├── Game_Information.cpp ├── Game_Information.h ├── README.md └── main.cpp ├── 014 └── README.md ├── LICENSE ├── README.md └── img └── 013-1.PNG /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cpprhtn/Cpp_Study/8f43ed704ce535fa0e94d9c5b3b0faf63dbf44ea/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /000/README.md: -------------------------------------------------------------------------------- 1 | # C에서 C++로 넘어가며... 2 | 3 | C언어는 절치 지향 언어라 부르며 4 | 5 | C++언어에 대해서는 객체 지향 언어라고 부릅니다. 6 | 7 | 이 둘의 차이는 무엇일까요. 8 | 9 | ## 객체지향과 절차지향언어의 차이 10 | 11 | 절차지향 언어는 코드를 순서대로 진행하는 것입니다. 12 | ```C++ 13 | int a; 14 | a = 5; 15 | ``` 16 | 위 코드는 돌아가지만 17 | ```C++ 18 | a = 5; 19 | int a; 20 | ``` 21 | 이번 코드는 돌아가지 않는 차이 입니다. 22 | 23 | 반대로 객체지향 언어는 위 두 코드 모드 잘 돌아가는 것을 볼 수 있습니다. 24 | 25 | 절차지향은 말 그대로 절차(순서)대로 코드를 진행한다지만 26 | 27 | 객체지향의 "객체"는 무엇을 의미하는 것일까요? 28 | 29 | 30 | 31 | C++에서 C에 비해 추가된 수많은 것들 중 가장 대표적인 예시로는 **Class**를 둘 수 있습니다. 32 | 33 | 이 클래스라는 것은 C언어에서의 구조체의 확장형이라 볼 수 있습니다. 34 | 35 | 클래스 역시 변수처럼 만들어지는 것이 있습니다. 36 | 37 | 이것을 **Object**라고 합니다. 38 | 39 | int형 a를 선언했을 때 a가 변수, 40 | class의 A를 선언했을 때 A를 오브젝트라고 부릅니다. 41 | 42 | 이 클래스와 오브젝트 개념이 객체와 직접적으로 연관이 되어있습니다. 43 | 44 | 이렇게 오브젝트를 만들고 다루는 것에 초점을 둔 것이 객체 지향 언어입니다. 45 | 46 | 47 | 48 | ## C++에서 추가된 기능 49 | 50 | > C언어에서 가능했던 거의 모든 코드들을 C++에서도 사용이 가능합니다 51 | 52 | 1. 변수를 생성할때, 초기화하는 방법 추가 53 | ```C++ 54 | //C ver 55 | int k = 1; 56 | float a = 3.14, b = 2.7; 57 | 58 | //C++ ver 59 | int k(1); 60 | float a(3.14), b(2.7); 61 | ``` 62 | 63 | 2. bool type의 변수 사용가능 64 | 65 | 3. 형변환 방법 추가 66 | ```C++ 67 | #include 68 | int main() 69 | { 70 | double d = 3.14; 71 | 72 | //C ver 73 | int n = (int)d; 74 | 75 | //C++ ver 76 | int n = static_cast(d); 77 | 78 | return 0; 79 | } 80 | 81 | 4. 입출력 추가 82 | ```C++ 83 | #include 84 | #include 85 | 86 | int main() 87 | { 88 | int a = 10; 89 | char b = "C"; 90 | float c = 3.14; 91 | 92 | //C ver 93 | printf("%d %c %f",a, b, c); 94 | 95 | //C++ ver 96 | cout << a << b << c << endl; 97 | 98 | return 0; 99 | } 100 | ``` 101 | 102 | 구구절절 설명을 했다만, 얼른 본격적으로 넘어가보도록 합시다 :) -------------------------------------------------------------------------------- /001/README.md: -------------------------------------------------------------------------------- 1 | # 입출력 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | C++형태의 입출력은 iostream 헤더를 불러와야하며, 이 헤더에는 std라는 namespace가 있습니다. 5 | (namespace는 다음강에서 다룹니다.) 6 | 7 | iostream 헤더의 많은 기능중 입출력에 대해 먼저 알아봅시다. 8 | 9 | cin은 입력, cout은 출력, endl은 개행을 의미하는 객체입니다. 10 | 11 | 이를 이용해서 두수의 합을 출력하는 프로그램을 짜 봅시다. 12 | 13 | ```C++ 14 | #include 15 | 16 | int main() 17 | { 18 | int x, y; 19 | 20 | std::cout << "두 정수를 입력하세요 :"; 21 | std::cin >> x >> y; 22 | int sum(x+y); 23 | std::cout << "두 수의 합은 " << sum << "입니다." << std::endl; 24 | } 25 | ``` 26 | 위 코드처럼 cout와 cin에서의 `<`, `>` 방향을 유의해서 외우시길 바랍니다. 27 | 28 | 큰 틀은 C언어와 변한 것이 없으며, scanf_s, printf대신 cin, cout를 쓰면 된다는 느낌입니다. 29 | 30 | 대신 C언어와의 차이점으로는, 형식지정자(%d, %f, ...)가 필요없다는 겁니다. 31 | 32 | 어떤 값이나 변수를 던져주면 그 자료형을 알아서 인식해서 알아서 입출력합니다. 33 | 34 | 35 | ### 소수점 출력 36 | ```C++ 37 | #include 38 | 39 | 40 | int main(){ 41 | 42 | double f; 43 | 44 | std::cout << "소수를 입력하세요: "; 45 | std::cin >> f; 46 | std::cout << "입력한 값은 " << f << "입니다." << std::endl; 47 | 48 | return 0; 49 | } 50 | ``` 51 | 3.14를 입력했다면 3.14가 출력될 것입니다. 52 | 그러나 3.140처럼 특정 자릿수까지 출력을 하고싶다면 아래와 같이 고칠 수 있습니다. 53 | ```C++ 54 | #include 55 | 56 | 57 | int main(){ 58 | 59 | double f; 60 | 61 | std::cout << "소수를 입력하세요: "; 62 | std::cin >> f; 63 | std::cout.setf(ios::fixed); 64 | std::cout.setf(ios::showpoint); 65 | std::cout.precision(3); 66 | std::cout << "입력한 값은 " << f << "입니다." << std::endl; 67 | 68 | return 0; 69 | } 70 | ``` 71 | 이렇게 했을경우 출력은 3.140이 됩니다. 72 | 출력되는 자릿수는 cout.precision()에 들어가는 숫자입니다. 73 | 74 | 75 | ### 실습 76 | 이를 바탕으로 3.14와 2.72의 수를 받아와 두 수의 곱을 출력하는 프로그램을 짜 주세요. 77 | ```C++ 78 | #include 79 | 80 | int main() 81 | { 82 | 83 | } 84 | ``` -------------------------------------------------------------------------------- /002/README.md: -------------------------------------------------------------------------------- 1 | # namespace 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | ```C++ 5 | #include 6 | int main() 7 | { 8 | std::cout <<"Hello, World!!"<< std::endl; 9 | } 10 | ``` 11 | 12 | 일반적인 IDE에서 새 파일을 만들면 위와 같은 코드를 볼 수 있을 것입니다. 13 | 14 | 15 | 위 코드를 먼저 분석해봅시다. 16 | 17 | ```C++ 18 | #include // iostream은 입출력을 위한 헤더파일입니다. 19 | 20 | int main() //시작함수(진입점) 21 | { 22 | 23 | std::cout << "Hello World!\n" << std::endl; 24 | 25 | //std::cout = 출력함수 26 | //std::endl = 개행함수 '\n' 27 | } 28 | ``` 29 | 30 | 여기에 각 함수앞에 std:: 형태가 붙어있는것을 볼 수 있습니다. 31 | std는 C++ 표준 라이브러리의 모든 함수, 객체 등이 정의된 namespace 입니다. 32 | 33 | 다른사람의 코드를 가져와 같이 사용하다보면 겹치는 함수가 많이 생기는데 34 | 이를 구분하기 위해 namespace라는 이름공간(직역)을 만든것입니다. 35 | 36 | 예를 들면 동명이인과 같습니다. 37 | 한 학교내에 이름이 같을수록 앞에 추가적인 특징등을 붙여 쓰는 경우가 많습니다. 38 | 이를 코드화 하면 아래와 같습니다. 39 | 40 | ```C++ 41 | #include 42 | int main() 43 | { 44 | _class_1::cpprhtn(); //1반의 cpprhtn 45 | _class_2::cpprhtn(); //2반의 cpprhtn 46 | //서로 다른사람을 호출한 것 47 | } 48 | ``` 49 | 위 처럼 구별을 위해 `namespace`를 사용합니다. 50 | 51 | 52 | ## using namespace std 53 | 일반적으로 혼자 코드를 짜서 함수가 겹치지 않는 상황일때도 std를 붙여주다보면 std를 수십개, 수백개를 써 주어야 하는 상황이 생길 수도 있습니다. 54 | using namespace std; 라는 문장을 통해서 std를 생략할 수 있습니다. 55 | 아래와 같이 사용합니다. 56 | 57 | ```C++ 58 | #include 59 | using namespace std; 60 | int main() 61 | { 62 | cout << "Hello, World!!"<< endl; 63 | } 64 | ``` 65 | 66 | 67 | 68 | C++ 표준 라이브러리는 엄청 많은 함수들이 존재하고 있습니다. 자칫 잘못하다가 이름을 겹치게 사용한다면, 고치느라 시간을 많이 잡아먹을 것입니다. 69 | 게다가 std 에는 매번 수 많은 함수들이 새롭게 추가되고 있기 때문에 C++ 버전이 바뀔 때 마다 기존에 잘 작동하던 코드가 이름 충돌로 인해 동작하지 않게되는 문제가 발생할 수 있습니다. 70 | 71 | 따라서 using namespace std; 보다, std:: 를 직접 앞에 붙여서 std 의 이름공간의 함수이다 라고 명시해주는 것이 좋습니다. -------------------------------------------------------------------------------- /003/README.md: -------------------------------------------------------------------------------- 1 | # pointer 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | 사실 포인터는 C++로 넘어오면서 레퍼런스와 혼동하여 쓰이기 쉽습니다. 5 | 6 | 그렇기에 둘의 차이를 확실하게 잡고 갈 생각입니다. 7 | 8 | 9 | 10 | - 포인터 (Pointer) 11 | 포인터는 어떠한 값을 저장하는 게 아닌 메모리 주소를 저장하는 변수다. 12 | 13 | ### 포인터 선언 14 | 15 | 포인터 변수는 일반 변수처럼 선언되며, 자료형과 변수 이름 사이에 별표(*)가 붙는다. 16 | > 자료형* 포인터 이름; 17 | ```C++ 18 | int* iPtr; // int형 포인터 19 | double* dPtr; // double형 포인터 20 | int* iPtr1, *iPtr2; // int형 두 개의 포인터 선언 21 | //여러 포인터 변수를 선언하는 경우 별표가 각 변수에 포함되어야 함. 22 | int* iPtr3, iPtr4; 23 | //ptr3은 int형 포인터, ptr4는 단순한 int 24 | ``` 25 | 26 | ### 포인터에 값 할당 27 | 포인터는 메모리 주소만 저장하므로, 포인터에 값을 할당할 때 그 값은 주소여야 한다. 28 | 포인터로 하는 가장 흔한 작업은 다른 변수의 주소를 저장하는 것이다. 29 | 30 | 변수의 주소를 얻으려면 주소 연산자(&)를 사용한다. 31 | > 포인터 = &변수; 32 | 33 | ```C++ 34 | int value = 5; int *ptr = &value; // 변수값의 주소로 ptr 초기화 35 | ``` 36 | ptr은 값으로 value 변수 값의 주소를 가지고 있다. 37 | 그러므로 ptr을 value 변수를 '가리키는' 값이라고 할 수 있다. 38 | 39 | ```C++ 40 | #include 41 | int main() 42 | { 43 | int value = 5; 44 | int *ptr = &value; // 변수 값의 주소로 ptr 초기화 45 | 46 | std::cout << &value << '\n'; // value 변수의 주소 출력 47 | std::cout << ptr << '\n'; // ptr 변수 값 출력 48 | 49 | return 0; 50 | } 51 | ``` 52 | 53 | 포인터 변수의 자료형은 가리키는 변수의 자료형과 같아야 한다. 54 | ```C++ 55 | int iValue = 5; 56 | double dValue = 7.0; 57 | int *iPtr = &iValue; // O 58 | double *dPtr = &dValue; // O 59 | iPtr = &dValue; // X 60 | dPtr = &iValue; // X 61 | ``` 62 | 63 | 다음 사항도 올바르지 않다. 64 | ```C++ 65 | int *ptr = 5; 66 | ``` 67 | 포인터가 주소만 보유할 수 있고 정수 리터럴 5에는 메모리 주소가 없기 때문이다. 68 | 위 코드를 시도하면 컴파일러는 정수를 정수 포인터로 변환할 수 없으므로 오류가 발생한다. 69 | 70 | 71 | C++에서는 포인터에 리터럴 메모리 주소를 직접 할당할 수 없다. 72 | ```C++ 73 | double *dPtr = 0x0012FF7C; // X 74 | ``` 75 | 76 | 77 | 78 | 어떤 것을 가리키는 포인터 변수가 있다면, 역참조 연산자 *를 통해 포인터가 가리키는 주소의 값을 알 수 있다. 79 | ```C++ 80 | int value = 5; 81 | std::cout << &value; // value의 주소를 출력 82 | std::cout << value; // value의 값을 출력 83 | 84 | int *ptr = &value; // ptr은 value를 가리킴 85 | std::cout << ptr; // ptr이 가리키는 주소를 출력 (&value) 86 | std::cout << *ptr; // ptr을 역참조함. ptr이 가리키는 주소의 값을 출력 (value) 87 | ``` 88 | 89 | 할당한 후에 포인터 값을 다른 값으로 재할당할 수 있다. 90 | ```C++ 91 | int value1 = 5; 92 | int value2 = 7; 93 | int *ptr; 94 | 95 | ptr = &value1; // value1의 주소를 가짐 96 | std::cout << *ptr; // 5 출력 97 | 98 | ptr = &value2; // value2의 주소를 가짐 99 | std::cout << *ptr; // 7 출력 100 | ``` 101 | 102 | ptr은 &value 값과 같다. 103 | *ptr은 value 값과 같다. 104 | 105 | *ptr은 value와 같게 취급되므로 마치 변수값인 것처럼 갓을 할당할 수 있다. 106 | ```C++ 107 | int value = 5; 108 | int *ptr = &value; 109 | *ptr = 7; 110 | std::cout << value; // 7 출력 111 | ``` -------------------------------------------------------------------------------- /004/README.md: -------------------------------------------------------------------------------- 1 | # pointer 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | 이번에는 `스마트 포인터`라는 것에 대해서 설명할 예정입니다. 5 | 6 | 기존의 C언어에서 할당과 해제 할때는 많은 오류와 데이터를 잡아먹는 상황이 자주 발생합니다. 7 | 8 | 이런 포인터 관련 오류를 최소화 하는 방법은 크게 3가지가 있습니다. 9 | 10 | 1. 표준 컨테이너 사용 11 | 표준 라이브러리나 유효성이 검증된 라이브러리를 사용하는 것입니다. 12 | 표준 라이브러리의 std::vector는 크기 조정 및 범위 검사를 포함한 동적 배열의 모든 기능을 제공하며 13 | 메모리를 자동으로 해제해줍니다. 14 | 15 | 2. 캡슐화 16 | 나중에 클래스에서 배우겠지만 캡슐화를 시켜 오류를 수정하는 방법이 있습니다. 17 | 18 | 3. 스마트 포인터를 사용 19 | 네 사실 이것이 이번 강의 주제입니다. 20 | 스마트 포인터를 거치면 기존의 타언어(C#, Java)처럼 메모리 해제라는 짐을 덜어줍니다. 21 | 22 | ## 스마트 포인터 23 | 이 스마트 포인터는 헤더에 정의되어 있습니다. 24 | 25 | 포인터는 get() 멤버 함수로 얻을 수 있고, reset() 멤버 함수를 통해서 메모리 해제를 할수 있습니다. 26 | 27 | 스마트 포인터를 왜 쓰는가? 28 | 29 | - error handling path가 여럿이라도 자원 관리가 편합니다. 30 | - 자원을 해제하는 주체가 명확하지 않을 경우에도 사용이 편리합니다. 31 | - 여러 custom memory allocator를 이용할 경우에, 객체를 사용하는 주체가 어떤 할당자를 사용하여 해제해야하는지 알 필요가 없습니다. 32 | 33 | ### 참조 카운트(reference count)? 34 | 참조 카운트: 해당 메모리를 참조하는 포인터가 몇개인지 나타내는 값을 의미 35 | 36 | #### auto_ptr 37 | 기존의 포인터가 있지만 C++03부터 auto_ptr이라는 스마트 포인터가 등장했습니다. 38 | 39 | 하지만 C++14부터 3가지의 타입이 추가되었고, 이제는 auto_ptr은 거의 사용하지 않습니다. 40 | 41 | ## shared_ptr 42 | 43 | ```C++ 44 | std::shared_ptr s_ptr (new Type); 45 | ``` 46 | 선언 방식은 위와 같습니다. 47 | 48 | std::shared_ptr 객체가 복사되어도 메모리 공간은 늘어나지 않습니다. 49 | 50 | shared_ptr로 선언된 포인터가 가리키는 메모리 공간은 참조 카운트가 0이 되는 순간 메모리를 해제하는 것입니다. 51 | 52 | shared_ptr 객체 하나가 소멸되더라도, 동일한 메모리 주소를 참조하고 있는 다른 shared_ptr 객체가 있으면 참조하고 있던 메모리 주소의 객체는 소멸되지 않습니다. 53 | 54 | shared_ptr에서는 순환참조가 일어날 수 있습니다. 55 | 56 | * 순환참조: 참조 카운트가 0이 되지 않아 메모리 해제가 되지 않는 상황 57 | - 예시: A와 B가 서로에 대한 shared_ptr을 들고 있으면 참조 카운트가 0이 되지 않아 메모리가 해제되지 않는 경우 58 | 59 | 60 | ```C++ 61 | #include 62 | #include 63 | using namespace std; 64 | 65 | int main() 66 | { 67 | shared_ptr s_ptr(new int); // 참조 카운트 1 68 | *s_ptr = 10; 69 | cout << "reference count: " << s_ptr.use_count() << endl; 70 | cout << *s_ptr << endl; 71 | 72 | shared_ptr temp_1 = s_ptr; // 참조 카운트 2 73 | *temp_1 += 1; // 11로 증가 74 | 75 | cout << "reference count: " << s_ptr.use_count() << endl; 76 | cout << *s_ptr << endl; // 증가된 값인 11 출력 77 | cout << *temp_1 << endl; 78 | 79 | shared_ptr temp_2 = temp_1; // 참조 카운트 3 80 | cout << "reference count: " << s_ptr.use_count() << endl; 81 | *temp_2 += 1; 82 | 83 | cout << *s_ptr << endl; // 증가된 값인 12 출력 84 | cout << *temp_1 << endl; 85 | cout << *temp_2 << endl; 86 | 87 | s_ptr.reset() //메모리 해제 88 | 89 | return 0; 90 | } 91 | ``` 92 | > 참조 카운트 1 93 | 94 | > 10 95 | 96 | > 참조 카운트 2 97 | 98 | > 11 99 | 100 | > 11 101 | 102 | > 참조 카운트 3 103 | 104 | > 12 105 | 106 | > 12 107 | 108 | > 12 109 | main() 함수를 종료하게 되면 참조 카운트가 0이 되어서 자동으로 메모리 공간이 해제됩니다. 110 | 참조된 값에 따라 카운트는 늘어나고 참조된 값을 변형하면 그 값에 따라 모두 값이 변합니다. 111 | 112 | 113 | 114 | ## unique_ptr 115 | 116 | ```C++ 117 | std::unique_ptr u_ptr(new Type); 118 | ``` 119 | 선언 방식은 위와 같습니다. 120 | 121 | unique_ptr은 참조한 데이터의 고유 소유권을 나타냅니다. 122 | 123 | 장점으론 기존 포인터에 비해 시간과 메모리에 대한 오버헤드가 없다는 것입니다. 124 | 125 | unique_ptr이 shared_ptr과 다른 점은 참조 카운트가 1을 넘을 수 없는 것입니다. 126 | 127 | 또한 복사는 불가능한 대신에, `move()`를 이용하여 이동이 가능합니다. 128 | 129 | ```C++ 130 | std::unique_ptr u_ptr(new int); // 참조 카운트 1 131 | std::unique_ptr temp_1 = u_ptr; // 에러 발생 132 | ``` 133 | 위 처럼 두 군데 이상의 포인터가 하나의 메모리 공간을 가리킨다면 컴파일 에러가 발생합니다. 134 | 135 | * unique_ptr의 기능으로 사용자정의 Deleter를 제공하는 기능이 있습니다. (구글링/설명생략) 136 | 137 | ```C++ 138 | #include 139 | #include 140 | using namespace std; 141 | 142 | int main() 143 | { 144 | unique_ptr u_ptr(new int); 145 | 146 | // auto temp = u_ptr; // 복사 X 147 | auto temp = move(u_ptr); // temp로 이동 148 | 149 | cout << u_ptr.get() << endl; // null_ptr가 되기 때문에 0 출력 150 | cout << temp.get() << endl; 151 | 152 | u_ptr.reset(); // 이미 이동되었기 때문에 동작 X 153 | temp.reset(); // 메모리 해제 154 | 155 | return 0; 156 | } 157 | ``` 158 | > 0x0 159 | 160 | > 0x7fee80c05830 161 | 162 | 포인터는 복사할 수 없지만, 포인터가 가리키는 객체는 복사할 수 있습니다. 163 | ```C++ 164 | #include 165 | #include 166 | using namespace std; 167 | 168 | int main() 169 | { 170 | unique_ptr u_ptr(new int(5)); 171 | 172 | auto temp = *u_ptr; 173 | auto& _refer = u_ptr; 174 | 175 | // 포인터 출력 176 | cout << u_ptr.get() << endl; 177 | cout << &temp << endl; 178 | cout << _refer.get() << endl; 179 | 180 | // 객체 출력 181 | cout << *u_ptr << endl; 182 | cout << temp << endl; 183 | cout << *_refer << endl; 184 | 185 | return 0; 186 | } 187 | ``` 188 | > 0x7fa1d4c05830 189 | 190 | > 0x7ffeed22c88c 191 | 192 | > 0x7fa1d4c05830 193 | 194 | > 5 195 | 196 | > 5 197 | 198 | > 5 199 | 200 | 201 | ## weak_ptr 202 | 203 | ```C++ 204 | std::weak_ptr w_ptr = s_ptr; 205 | { 206 | // 참조한 객체 사용 207 | } 208 | // w_ptr 소멸 209 | ``` 210 | 선언 방식은 위와 같습니다. 211 | 212 | weak_ptr는 shared_ptr의 객체를 참조하지만, shared_ptr의 참조 카운트를 올리지 않는 것입니다. 213 | 214 | std::weak_ptr은 포인터에 직접 접근을 할 수 없기 때문에 lock() 멤버 함수로 std::shared_ptr 객체를 생성한 다음 그 객체를 통해서 포인터에 접근해야 합니다. 215 | 216 | 이 weak::lock()을 통해서 shared_ptr의 순환참조 문제를 해결할 수 있습니다. 217 | 218 | ```C++ 219 | // shared 참조 카운트 -> s_cnt 220 | // weak 참조 카운트 -> w_cnt 221 | #include 222 | #include 223 | using namespace std; 224 | 225 | int main() 226 | { 227 | shared_ptr s_ptr(new int); 228 | 229 | // weak_ptr가 s_ptr으로부터 복사 생성 (참조) 230 | weak_ptr w_ptr = s_ptr; // s_cnt = 1, w_cnt = 1 231 | { 232 | // w_ptr가 참조하고 있던 s_ptr를 weak_ptr::lock 메서드를 이용해 s_ptr_2가 참조 233 | shared_ptr s_ptr_2 = w_ptr.lock(); // s_cnt = 2, w_cnt = 1 234 | if (s_ptr_2) 235 | { 236 | 237 | } 238 | // s_ptr_2 소멸 239 | // s_cnt = 1, w_cnt = 1 240 | } 241 | // w_ptr 소멸 242 | 243 | s_ptr.reset(); // 메모리 해제 244 | 245 | return 0; 246 | } 247 | ``` -------------------------------------------------------------------------------- /005/README.md: -------------------------------------------------------------------------------- 1 | # reference 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | C++에서 등장했으며, 포인터와 비슷하게 생긴 `레퍼런스`라는 것을 알아봅시다. 5 | 6 | 이것 역시 포인터처럼 주소값을 가지는데, 유사하면서도 많은 차이점이 있다. 7 | 8 | ### 레퍼런스 선언 9 | > &변수명 = 다른변수 10 | 11 | 12 | 반드시 처음에 초기화해야 하며(다른 변수를 가리키게 함) 13 | 그 이후는 자신이 가리키는 변수를 바꿀 수 없다. 14 | 15 | NULL값으로 레퍼런스를 초기화할 수 없다. 16 | 17 | 레퍼런스가 어떤 변수에 새로운 이름을 부여한다고 생각하면 된다. 18 | 19 | ```C++ 20 | #include 21 | 22 | int main() 23 | { 24 | int a = 1; 25 | int &b = a; 26 | 27 | printf("%d %d\n", a, b); // 1 1 28 | printf("%p %p\n", &a, &b); // 006AD1F8 006AD1F8 29 | 30 | int c(3); 31 | &b = c; // Error 32 | int &d = '\0' // Error 33 | 34 | return 0; 35 | } 36 | ``` 37 | 위에선 a라는 변수에 b이라는 새로운 이름을 부여한 것을 볼 수 있다. 38 | 39 | 40 | ### 레퍼런스와 포인터의 차이점 41 | 42 | 레퍼런스는 반드시 처음에 초기화해야 하며, 다시는 가리키는 주소를 못 바꾸고, 배열을 만들 수 없다. 43 | 44 | 포인터는 값 자체에 접근하려면 *를 붙여야 하지만 레퍼런스는 그러지 않아도 된다. 45 | 46 | 47 | 48 | 아래 코드를 보면서 C언어의 포인터보다 레퍼런스를 사용하면 가독성이 높아지는 것을 알 수 있습니다. 49 | ```C 50 | #include 51 | 52 | void swap(int *p, int *q) 53 | { 54 | int temp; 55 | temp = *p; 56 | *p = *q; 57 | *q = temp; 58 | } 59 | 60 | int main() 61 | { 62 | int x = 1, y = 2; 63 | 64 | swap(&x, &y); 65 | printf("%d %d\n",x, y); 66 | 67 | return 0; 68 | } 69 | ``` 70 | 71 | ```C++ 72 | #include 73 | 74 | void swap(int &p, int &q) 75 | { 76 | int temp; 77 | temp = p; 78 | p = q; 79 | q = temp; 80 | } 81 | 82 | int main() 83 | { 84 | int x(1), y(2); 85 | 86 | swap(x, y); 87 | printf("%d %d\n",x, y); 88 | 89 | return 0; 90 | } 91 | ``` 92 | 93 | 94 | 아래와 같이 400byte 크기의 구조체가 있다고 합시다. 95 | 이때 sum()이라는 함수에서 매개변수로 이 구조체를 호출한다면 96 | 호출할때마다 400byte크기의 값이 복사될 것이다. 97 | 98 | 이 문제를 해결하기 위해서 포인터를 사용한다면 두번째 예제처럼 코드를 바꿀 수 있습니다. 99 | 이때는 매개변수만 포인터로 바뀌었지만, 매개변수의 주소값만 넘겨주므로 포인터의 크기인 4byte만 사용하게 됩니다. 100 | 101 | 세번째 코드에서는 레퍼런스를 사용하여 구현한 것입니다. 102 | 레퍼런스 역시 4byte를 사용하지만, 포인터보다 가독성이 더 높은 것을 알 수 있습니다. 103 | 104 | ```C 105 | #include 106 | 107 | typedef struct arr100 108 | { 109 | int arr[100]; 110 | }Arr100; 111 | 112 | int sum(Arr100 temp) 113 | { 114 | int sum = 0; 115 | for (int i = 0; i < 100; i++) 116 | { 117 | sum += temp.arr[i]; 118 | } 119 | 120 | return sum; 121 | } 122 | 123 | int main() 124 | { 125 | Arr A; 126 | int Sum = sum(A); 127 | 128 | return 0; 129 | } 130 | ``` 131 | 132 | 133 | ```C 134 | #include 135 | 136 | typedef struct arr100 137 | { 138 | int arr[100]; 139 | }Arr100; 140 | 141 | int sum(Arr100 *temp) 142 | { 143 | int sum = 0; 144 | for (int i = 0; i < 100; i++) 145 | { 146 | sum += temp -> arr[i]; 147 | } 148 | 149 | return sum; 150 | } 151 | 152 | int main() 153 | { 154 | Arr A; 155 | int Sum = sum(&A); 156 | 157 | return 0; 158 | } 159 | ``` 160 | 161 | ```C++ 162 | #include 163 | 164 | typedef struct arr100 165 | { 166 | int arr[100]; 167 | }Arr100; 168 | 169 | int sum(Arr100 &temp) 170 | { 171 | int sum = 0; 172 | for (int i = 0; i < 100; i++) 173 | { 174 | sum += temp.arr[i]; 175 | } 176 | 177 | return sum; 178 | } 179 | 180 | int main() 181 | { 182 | Arr A; 183 | int Sum = sum(A); 184 | 185 | return 0; 186 | } 187 | ``` 188 | 189 | 190 | 191 | ### 예상해보기 192 | 아래 코드의 결과를 예상해봅시다. 193 | ```C++ 194 | #include 195 | 196 | int main() 197 | { 198 | int n = 1; 199 | int &m = n; 200 | 201 | printf("%d %d\n", n, m); 202 | 203 | n = 7; 204 | printf("%d %d\n", n, m); 205 | 206 | m = 9; 207 | printf("%d %d\n", n, m); 208 | 209 | return 0; 210 | } 211 | ``` -------------------------------------------------------------------------------- /006/README.md: -------------------------------------------------------------------------------- 1 | # string 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | 이번에는 string에 대해 알아보겠습니다. 5 | 6 | string 자료형역시 C++로 넘어오면서 만들어진 자료형 중에 하나입니다. 7 | 8 | C언어에서 문자열은 char arr[]; 형태였습니다. 9 | 10 | 그러나 C++에서는 cin을 통해 배열을 입력받기 난해하므로 11 | 12 | string헤더를 통해서 string이라는 type를 만든 것입니다. 13 | 14 | 우선 string 문자열을 통해 자기소개하는 코드를 짜봅시다. 15 | ```C++ 16 | #include 17 | #include 18 | 19 | int main(){ 20 | 21 | std::string str; 22 | 23 | std::cout << "문자열을 입력하세요: "; 24 | std::cin >> str; 25 | std::cout << "입력한 문자열은 " << str << "입니다." << std::endl; 26 | 27 | return 0; 28 | } 29 | ``` 30 | > 문자열을 입력하세요: cpprhtn 31 | 32 | > 입력한 문자열은 cpprhtn입니다. 33 | 34 | 위와같이 출력됨을 볼 수 있습니다. 35 | 36 | 이번에는 문자열을 합쳐보도록 하겠습니다. 37 | C에서는 strcat(a, b) 등의 형태로 문자열을 합쳤던 것을 생각하며 아래 코드를 봅시다. 38 | ```C++ 39 | #include 40 | #include 41 | 42 | int main(){ 43 | 44 | std::string str1, str2, str3; 45 | 46 | std::cout << "단어 2개를 입력하세요: "; 47 | std::cin >> str1 >> str2; 48 | str3 = str1 + str2; 49 | std::cout << "합쳐진 단어는 " << str3 << "입니다." << std::endl; 50 | 51 | return 0; 52 | } 53 | ``` 54 | > 단어 2개를 입력하세요: cpp rhtn 55 | 56 | > 합쳐진 단어는 cpprhtn입니다. 57 | 58 | 위처럼 string에서는 + 연산자로 문자열을 합칠 수 있습니다. 59 | 60 | 61 | 또한 아래와 같이 string은 배열처럼 접근할 수도 있습니다. 62 | ```C++ 63 | #include 64 | #include 65 | 66 | int main(){ 67 | 68 | std::string str = "cpprhtn"; 69 | 70 | std::cout << "입력한 문자열은 " << str << "입니다." << std::endl; 71 | std::cout << str[0] << std::endl << str[1] << std::endl << str[2]; 72 | 73 | return 0; 74 | } 75 | ``` 76 | 77 | 78 | 79 | C에서처럼 C++에서도 `getline`을 이용하여 한줄 전체를 입력받을 수 있습니다. 80 | ```C++ 81 | #include 82 | #include 83 | 84 | int main(){ 85 | 86 | std::string str; 87 | 88 | std::cout << "문자열을 입력하세요: "; 89 | std::getline(std::cin, str); 90 | std::cout << str << std::endl; 91 | 92 | return 0; 93 | } 94 | ``` 95 | > 문자열을 입력하세요: I love cpp 96 | 97 | > I love cpp 98 | 99 | 100 | 마지막으로는 문자열 길이를 확인해보도록 하겠습니다. 101 | 102 | ```C++ 103 | #include 104 | #include 105 | 106 | int main(){ 107 | 108 | std::string str; 109 | 110 | std::cout << "문자열을 입력하세요: "; 111 | std::getline(cin, str); 112 | std::cout << str << std::endl; 113 | std::cout << "문자열 길이: " << str.length() << std::endl; 114 | 115 | return 0; 116 | } 117 | ``` 118 | > 문자열을 입력하세요: I love cpp 119 | 120 | > 문자열 길이: 10 -------------------------------------------------------------------------------- /007/README.md: -------------------------------------------------------------------------------- 1 | # class 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | 이번에는 class에 대해 알아보겠습니다. 5 | 6 | 0강에서 잠시 언급은 했으나 이제부터 조금더 자세히 알아봅시다. 7 | 8 | 구조체를 만들듯이 사용하면 되지만, public, private, friend등의 추가적인 선언이 필요합니다. 9 | 10 | 여기서 public은 공공의, 즉 외부에서 자유롭게 접근가능함을 의미합니다. 11 | 12 | 아래의 코드를 보면서 익혀봅시다. 13 | 14 | ```C++ 15 | #include 16 | using namespace std; 17 | 18 | class New_Class{ 19 | public: 20 | int i; 21 | double d; 22 | }; 23 | 24 | int main(){ 25 | 26 | New_Class A; //object 27 | A.i = 1; 28 | A.d = 3.14; 29 | 30 | return 0; 31 | } 32 | ``` 33 | 구조체와 거의 비슷하다고 볼 수 있습니다. 34 | 여기서 클래스 자료형을 가진 변수를 object라고 부릅니다. 35 | 36 | 37 | 구조체와 마찬가지로, 같은 클래스를 자료형으로 취하는 서로 다른 오브젝트는 멤버 변수의 값이 독립적으로 존재할 수 있습니다. 38 | 39 | ```C++ 40 | #include 41 | using namespace std; 42 | 43 | class New_Class{ 44 | public: 45 | int i; 46 | double d; 47 | }; 48 | 49 | int main(){ 50 | 51 | New_Class A, B; //object 52 | A.i = 1; 53 | A.d = 3.14; 54 | B.i = 2; 55 | B.d = 6.28; 56 | 57 | cout << "object A: " << A.n << ", " << A.f << endl; 58 | cout << "object B: " << B.n << ", " << B.f << endl; 59 | return 0; 60 | } 61 | ``` 62 | > object A: 1, 3.14 63 | 64 | > object B: 2, 6.28 65 | 66 | 67 | 이번에는 여러개의 클래스를 만들어봅시다. 68 | ```C++ 69 | #include 70 | using namespace std; 71 | 72 | class F_Class{ 73 | public: 74 | int i; 75 | double d; 76 | }; 77 | 78 | class S_Class{ 79 | public: 80 | char c; 81 | }; 82 | 83 | int main(){ 84 | 85 | F_Class A; 86 | S_Class B; 87 | A.i = 1; 88 | A.d = 3.14; 89 | B.c = 'k'; 90 | 91 | cout << "object A: " << A.i << ", " << A.d << endl; 92 | cout << "object B: " << B.c << endl; 93 | return 0; 94 | } 95 | ``` 96 | > object A: 1, 3.14 97 | 98 | > object B: k 99 | 100 | 101 | 이제는 중요한 개념중 하나인 멤버 함수에 대해서 알아봅시다. 102 | 멤버 함수는 클래스안에서 함수를 만드는 형태인데, 멤버 변수를 불러오듯이 멤버 함수도 불러오면 됩니다. 103 | 아래의 코드는 두 수의 합을 구하는 멤버 함수를 포함한 것입니다. 104 | ```C++ 105 | #include 106 | using namespace std; 107 | 108 | class F_Class{ 109 | public: 110 | int x, y; 111 | int sum() 112 | { 113 | return x+y; 114 | } 115 | }; 116 | 117 | int main(){ 118 | 119 | F_Class A, B; 120 | A.x = 1; 121 | A.y = 2; 122 | B.x = 10; 123 | B.y = -15; 124 | 125 | int sum_A, sum_B; 126 | sum_A = A.sum(); 127 | sum_B = B.sum(); 128 | 129 | cout << "A의 합: " << sum_A << endl; 130 | cout << "B의 합: " << sum_B << endl; 131 | 132 | return 0; 133 | } 134 | ``` 135 | > A의 합: 3 136 | 137 | > B의 합: -5 138 | 139 | 140 | 이번에는 멤버 함수를 더 만들어 보겠습니다. 141 | ```C++ 142 | #include 143 | using namespace std; 144 | 145 | class F_Class{ 146 | public: 147 | int x, y; 148 | int sum() 149 | { 150 | return x+y; 151 | } 152 | void print() 153 | { 154 | cout << "x: " << x << ", y: " << y << endl; 155 | } 156 | }; 157 | 158 | int main(){ 159 | 160 | F_Class A, B; 161 | A.x = 1; 162 | A.y = 2; 163 | B.x = 10; 164 | B.y = -15; 165 | 166 | int sum_A, sum_B; 167 | sum_A = A.sum(); 168 | sum_B = B.sum(); 169 | 170 | cout << "A의 합: " << sum_A << endl; 171 | A.print(); 172 | cout << "B의 합: " << sum_B << endl; 173 | B.print(); 174 | 175 | return 0; 176 | } 177 | ``` 178 | > A의 합: 3 179 | 180 | > x: 1, y: 2 181 | 182 | > B의 합: -5 183 | 184 | > x: 10, y: -15 185 | 186 | 187 | 188 | 선언은 클래스 안에 하고, 정의는 역시 가장 바깥쪽 지역에 합니다. 189 | 이때 일반 함수와 다른 점은, 멤버 함수임을 표시하기 위해 함수명 바로 앞에 "클래스명::"을 붙여야 합니다. 190 | ```C++ 191 | #include 192 | using namespace std; 193 | 194 | class F_Class{ 195 | public: 196 | int x, y; 197 | int sum(); 198 | void print(); 199 | }; 200 | 201 | int main(){ 202 | 203 | F_Class A, B; 204 | A.x = 1; 205 | A.y = 2; 206 | B.x = 10; 207 | B.y = -15; 208 | 209 | int sum_A, sum_B; 210 | sum_A = A.sum(); 211 | sum_B = B.sum(); 212 | 213 | cout << "A의 합: " << sum_A << endl; 214 | A.print(); 215 | cout << "B의 합: " << sum_B << endl; 216 | B.print(); 217 | 218 | return 0; 219 | } 220 | 221 | int F_Class::sum() 222 | { 223 | return x + y; 224 | } 225 | 226 | void F_Class::print() 227 | { 228 | cout << "x: " << x << ", y: " << y << endl; 229 | } 230 | ``` -------------------------------------------------------------------------------- /008/README.md: -------------------------------------------------------------------------------- 1 | # class 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | 클래스 내부의 public, private, friend 중에 이번에는 private도 함께 사용해 보겠습니다. 5 | 6 | private, 개인적인 의미로써, 외부에서의 접근이 제한됩니다. 7 | 8 | 아래 코드를 보면서 private도 이해해봅시다. 9 | 10 | ```C++ 11 | #include 12 | using namespace std; 13 | 14 | class New_Class{ 15 | private: 16 | int i; 17 | double d; 18 | }; 19 | 20 | int main(){ 21 | 22 | New_Class A, B; //object 23 | 24 | A.i = 1; //Error 25 | A.d = 3.14; //Error 26 | B.i = 2; //Error 27 | B.d = 6.28; //Error 28 | 29 | cout << "object A: " << A.n << ", " << A.f << endl; 30 | cout << "object B: " << B.n << ", " << B.f << endl; 31 | return 0; 32 | } 33 | ``` 34 | 바로 이전 6강의 첫번째 코드를 가져와보았는데, class부분에서 public 대신 private가 선언된 것을 볼 수 있습니다. 35 | 36 | 그러나 이 코드를 실행해보면 멤버 변수에 접근하는 부분에서 에러가 뜹니다. 37 | 38 | private 멤버 변수에 바로 접근을 할 수 없기 때문에 멤버 함수를 통해 접근할 필요가 있습니다. 39 | 40 | ```C++ 41 | #include 42 | using namespace std; 43 | 44 | class New_Class{ 45 | private: 46 | int i; 47 | double d; 48 | 49 | public: 50 | void set_i(int); 51 | void set_d(double); 52 | int get_i(); 53 | int get_d(); 54 | }; 55 | 56 | int main(){ 57 | 58 | New_Class A, B; //object 59 | 60 | A.set_i(1); 61 | A.set_d(3.14); 62 | B.set_i(2); 63 | B.set_d(6.28); 64 | 65 | cout << "A.i: " << A.get_i() << endl; 66 | cout << "B.d: " << B.get_d() << endl; 67 | 68 | return 0; 69 | } 70 | 71 | void New_Class::set_i(int x){ 72 | i = x; 73 | } 74 | 75 | void New_Class::set_d(double y){ 76 | d = y; 77 | } 78 | 79 | int New_Class::get_i(){ 80 | return i; 81 | } 82 | 83 | int New_Class::get_d(){ 84 | return d; 85 | } 86 | ``` 87 | > A.i: 1 88 | 89 | > B.d: 6 90 | 91 | ### 왜 private를 사용하는가 92 | 93 | class의 private는 C++ 언어에서 매우 중요한 요소입니다. 94 | 95 | 객체 지향 언어의 특성중 하나인 은닉성에 큰 영향을 주기 때문입니다. 96 | 97 | 여기서 말하는 은닉성은 사용자가 프로그램을 사용하면서 필요한 최소한의 정보만 제공하고, 98 | 99 | 그러한 기능이 실행되는 과정이나 절차는 최대한 가려서 사용자가 알지 못하게 한다는 것입니다. 100 | 101 | 이를 캡슐화라고도 부릅니다. 102 | 103 | 이러한 은닉성을 지키기 위해서 public대신 private를 사용한다고 볼 수 있습니다. 104 | 105 | 아래는 배열을 역순으로 정렬(리버스) 해주는 코드를 짠 것입니다. 106 | ```C++ 107 | #include 108 | #define MAX 10 109 | using namespace std; 110 | 111 | class Array10{ 112 | public: 113 | void set_arr(int*); 114 | void reverse(); 115 | int get(int); 116 | private: 117 | int arr[MAX]; 118 | void swap(int&, int&); 119 | }; 120 | 121 | int main() 122 | { 123 | Array10 A; 124 | int temp_arr[10] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3}; 125 | 126 | A.set_arr(temp_arr); 127 | for(int i=0; i 2 | #include "Array10.h" 3 | using namespace std; 4 | 5 | void Array10::set_arr(int *temp){ 6 | for(int i=0; i 2 | #include "Dot.h" 3 | using namespace std; 4 | 5 | void Dot::set(int x1, int y1){ 6 | x = x1; 7 | y = y1; 8 | } 9 | 10 | void Dot::setX(int x1){ 11 | x = x1; 12 | } 13 | 14 | void Dot::setY(int y1){ 15 | y = y1; 16 | } 17 | 18 | int Dot::getX(){ 19 | return x; 20 | } 21 | 22 | int Dot::getY(){ 23 | return y; 24 | } -------------------------------------------------------------------------------- /009/Dot.h: -------------------------------------------------------------------------------- 1 | class Dot{ 2 | private: 3 | int x, y; 4 | public: 5 | void set(int, int); 6 | void setX(int); 7 | void setY(int); 8 | int getX(); 9 | int getY(); 10 | }; -------------------------------------------------------------------------------- /009/Location.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Location.h" 3 | using namespace std; 4 | 5 | void Location::setQ(int x1, int y1){ 6 | Q.setX(x1); 7 | Q.setY(y1); 8 | } 9 | 10 | void Location::setR(int x1, int y1){ 11 | R.setX(x1); 12 | R.setY(y1); 13 | } 14 | 15 | void Location::print(){ 16 | cout << "Q(" < 23 | #define MAX 10 24 | using namespace std; 25 | 26 | class Array10{ 27 | public: 28 | void set_arr(int*); 29 | void reverse(); 30 | int get(int); 31 | private: 32 | int arr[MAX]; 33 | void swap(int&, int&); 34 | }; 35 | 36 | int main() 37 | { 38 | Array10 A; 39 | int temp_arr[10] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3}; 40 | 41 | A.set_arr(temp_arr); 42 | for(int i=0; i 79 | 80 | ```C++ 81 | class Array10{ 82 | public: 83 | void set_arr(int*); 84 | void reverse(); 85 | int get(int); 86 | private: 87 | int arr[MAX]; 88 | void swap(int&, int&); 89 | }; 90 | ``` 91 | 92 | 93 | 94 | ```C++ 95 | #include 96 | #include "Array10.h" 97 | using namespace std; 98 | 99 | void Array10::set_arr(int *temp){ 100 | for(int i=0; i 121 | 122 | ```C++ 123 | #include 124 | #include "Array10.h" 125 | using namespace std; 126 | 127 | int main() 128 | { 129 | Array10 A; 130 | int temp_arr[10] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3}; 131 | 132 | A.set_arr(temp_arr); 133 | for(int i=0; i 165 | 166 | ```Cpp 167 | class Dot{ 168 | private: 169 | int x, y; 170 | public: 171 | void set(int, int); 172 | void setX(int); 173 | void setY(int); 174 | int getX(); 175 | int getY(); 176 | }; 177 | ``` 178 | 179 | 180 | 181 | ```Cpp 182 | #include 183 | #include "Dot.h" 184 | using namespace std; 185 | 186 | void Dot::set(int x1, int y1){ 187 | x = x1; 188 | y = y1; 189 | } 190 | 191 | void Dot::setX(int x1){ 192 | x = x1; 193 | } 194 | 195 | void Dot::setY(int y1){ 196 | y = y1; 197 | } 198 | 199 | int Dot::getX(){ 200 | return x; 201 | } 202 | 203 | int Dot::getY(){ 204 | return y; 205 | } 206 | ``` 207 | 208 | 209 | 210 | ```Cpp 211 | #include "Dot.h" //Dot.h 파일을 선언 212 | 213 | class Location{ 214 | private: 215 | Dot Q, R; //Dot 클래스 사용 216 | public: 217 | void setQ(int, int); 218 | void setR(int, int); 219 | void print(); 220 | }; 221 | ``` 222 | 223 | 224 | 225 | ```Cpp 226 | #include 227 | #include "Location.h" 228 | using namespace std; 229 | 230 | void Location::setQ(int x1, int y1){ 231 | Q.setX(x1); 232 | Q.setY(y1); 233 | } 234 | 235 | void Location::setR(int x1, int y1){ 236 | R.setX(x1); 237 | R.setY(y1); 238 | } 239 | 240 | void Location::print(){ 241 | cout << "Q(" < 247 | 248 | ```Cpp 249 | #include 250 | #include "Location.h" //Location.h에서 Dot.h를 include했기에 선언할 필요 없음 251 | using namespace std; 252 | 253 | int main(){ 254 | //Dot 클래스 사용 255 | Dot P; 256 | P.set(3, 4); 257 | cout << "P(" << P.getX() << ", " << P.getY() << ")" << endl; 258 | 259 | //Dot 클래스를 사용해 만든 Location 클래스 사용 260 | Location Two_dot; 261 | Two_dot.setQ(-1, 2); 262 | Two_dot.setR(-5, -5); 263 | Two_dot.print(); 264 | 265 | return 0; 266 | } 267 | ``` 268 | > P(3, 4) 269 | 270 | > Q(-1, 2) 271 | 272 | > R(-5, -5) 273 | 274 | #### 메인함수의 내용중 일부이다. 275 | ```Cpp 276 | //Dot 클래스 사용 277 | Dot P; 278 | P.set(3, 4); 279 | cout << "P(" << P.getX() << ", " << P.getY() << ")" << endl; 280 | ``` 281 | Dot 클래스에서 점 하나의 좌표를 저장할 수 있음을 알 수 있다. 282 | 283 | 이를 이용해서 P 점의 좌표를 출력하는 과정을 위 처럼 짤 수 있다. 284 | 285 | #### 메인함수의 내용중 일부이다. 286 | ```Cpp 287 | //Dot 클래스를 사용해 만든 Location 클래스 사용 288 | Location Two_dot; 289 | Two_dot.setQ(-1, 2); 290 | Two_dot.setR(-5, -5); 291 | Two_dot.print(); 292 | ``` 293 | 이번에는 Location 클래스에서 점의 좌표를 저장하고, 출력하는 함수까지 만들었다. 294 | 295 | 이렇게 되면 위 코드처럼 내부적인 동작이 드러나지 않고 좌표의 세팅과 출력이 모두 이루어진다. 296 | 297 | 은닉성도 만족하고, main함수에서의 코드도 깔끔해지는것을 볼 수 있다. -------------------------------------------------------------------------------- /009/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Array10.h" 3 | using namespace std; 4 | 5 | int main() 6 | { 7 | Array10 A; 8 | int temp_arr[10] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3}; 9 | 10 | A.set_arr(temp_arr); 11 | for(int i=0; i 2 | #include "Location.h" //Location.h에서 Dot.h를 include했기에 선언할 필요 없음 3 | using namespace std; 4 | 5 | int main(){ 6 | //Dot 클래스 사용 7 | Dot P; 8 | P.set(3, 4); 9 | cout << "P(" << P.getX() << ", " << P.getY() << ")" << endl; 10 | 11 | //Dot 클래스를 사용해 만든 Location 클래스 사용 12 | Location Two_dot; 13 | Two_dot.setQ(-1, 2); 14 | Two_dot.setR(-5, -5); 15 | Two_dot.print(); 16 | 17 | return 0; 18 | } -------------------------------------------------------------------------------- /010/Game_Information.cpp: -------------------------------------------------------------------------------- 1 | #include "Game_Information.h" 2 | 3 | void info::set(int n){ 4 | age = n; 5 | } 6 | 7 | void info::set(string name){ 8 | ID = name; 9 | } 10 | 11 | void info::set(string name, int n){ 12 | age = n; 13 | ID = name; 14 | } 15 | 16 | void info::print(){ 17 | cout << "아이디: " << ID << ", 나이: " << age << endl; 18 | } -------------------------------------------------------------------------------- /010/Game_Information.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | class info{ 6 | public: 7 | // set 함수에서 오버로딩 된 것을 볼 수 있다. 8 | void set(string); 9 | void set(int); 10 | void set(string, int); 11 | 12 | void print(); 13 | private: 14 | int age; 15 | string ID; 16 | }; -------------------------------------------------------------------------------- /010/README.md: -------------------------------------------------------------------------------- 1 | # Overloading 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | 이번에는 오버로딩에 대해 알아보겠습니다. 5 | 6 | 오버로딩은 동일한 이름을 가진 함수를 여러 개 선언 & 정의하는 것입니다. 7 | 8 | 동일한 함수명을 가진다면 어떻게 구분하느냐? 9 | 10 | 아래 코드를 보면서 이해해봅시다. 11 | 12 | 13 | 14 | ```cpp 15 | #include 16 | using namespace std; 17 | 18 | int sum(int x, int y){ 19 | return x+y; 20 | } 21 | 22 | int sum(int x, int y, int z){ 23 | return x+y+z; 24 | } 25 | 26 | int main(){ 27 | 28 | cout << sum(1, 2) << endl; 29 | cout << sum(2, 3, 5) << endl; 30 | 31 | return 0; 32 | } 33 | ``` 34 | > 3 35 | 36 | > 10 37 | 38 | 위의 코드에서 `sum`이라는 함수를 2개 만들었습니다. 39 | 40 | 둘의 다른점은 함수 속의 매개변수의 리스트가 다른 것입니다. 41 | 42 | 여기서 매개변수의 리스트가 다른 경우는 크게 2가지 입니다. 43 | 1. 매개변수의 개수가 다름 44 | 2. 매개변수 개수는 같지만, 매개변수의 자료형이 다름 45 | 46 | 47 | 이를 이용해서 게임의 아이디, 나이, 혹은 둘 전부를 쓸 수 있도록 함수를 만들어 봅시다. 48 | 49 | 50 | 51 | ```cpp 52 | #include 53 | #include 54 | using namespace std; 55 | 56 | class info{ 57 | public: 58 | // set 함수에서 오버로딩 된 것을 볼 수 있다. 59 | void set(string); 60 | void set(int); 61 | void set(string, int); 62 | 63 | void print(); 64 | private: 65 | int age; 66 | string ID; 67 | }; 68 | ``` 69 | 70 | 71 | 72 | ```cpp 73 | #include "Game_Information.h" 74 | 75 | void info::set(int n){ 76 | age = n; 77 | } 78 | 79 | void info::set(string name){ 80 | ID = name; 81 | } 82 | 83 | void info::set(string name, int n){ 84 | age = n; 85 | ID = name; 86 | } 87 | 88 | void info::print(){ 89 | cout << "아이디: " << ID << ", 나이: " << age << endl; 90 | } 91 | ``` 92 | 93 | 94 | 95 | ```cpp 96 | #include 97 | #include "Game_Information.h" 98 | using namespace std; 99 | 100 | int main(){ 101 | 102 | cout << "LOL" << endl; 103 | 104 | info A; 105 | A.set("Hide on bush", 20); 106 | A.print(); 107 | 108 | A.set(17); 109 | A.print(); 110 | 111 | A.set("SKTT1 Faker"); 112 | A.print(); 113 | 114 | return 0; 115 | } 116 | ``` 117 | > LOL 118 | 119 | > 아이디: Hide on bush, 나이: 20 120 | 121 | > 아이디: Hide on bush, 나이: 17 122 | 123 | > 아이디: SKTT1 Faker, 나이: 17 124 | 125 | 이런식으로 만들어 보았습니다. 126 | 127 | 오버로딩은 생성자 개념에서 중요한 역할을 하기 때문에 잘 이해하고 넘어가면 좋겠습니다. -------------------------------------------------------------------------------- /010/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Game_Information.h" 3 | using namespace std; 4 | 5 | int main(){ 6 | 7 | cout << "LOL" << endl; 8 | 9 | info A; 10 | A.set("Hide on bush", 20); 11 | A.print(); 12 | 13 | A.set(17); 14 | A.print(); 15 | 16 | A.set("SKTT1 Faker"); 17 | A.print(); 18 | 19 | return 0; 20 | } -------------------------------------------------------------------------------- /010/sum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int sum(int x, int y){ 5 | return x+y; 6 | } 7 | 8 | int sum(int x, int y, int z){ 9 | return x+y+z; 10 | } 11 | 12 | int main(){ 13 | 14 | cout << sum(1, 2) << endl; 15 | cout << sum(2, 3, 5) << endl; 16 | 17 | return 0; 18 | } -------------------------------------------------------------------------------- /011/Game_Information.cpp: -------------------------------------------------------------------------------- 1 | #include "Game_Information.h" 2 | 3 | // 기본 생성자 4 | info::info(){ // 기본 생성자 정의 5 | age = 0; 6 | ID = ""; 7 | } 8 | 9 | void info::set(int n){ 10 | age = n; 11 | } 12 | 13 | void info::set(string name){ 14 | ID = name; 15 | } 16 | 17 | void info::set(string name, int n){ 18 | age = n; 19 | ID = name; 20 | } 21 | 22 | void info::print(){ 23 | cout << "아이디: " << ID << ", 나이: " << age << endl; 24 | } 25 | 26 | 27 | // 생성자 오버로딩 28 | Users::Users():name("비공개"),years(2020){ 29 | 30 | } 31 | 32 | Users::Users(string names):name(names),years(2020){ 33 | 34 | } 35 | 36 | Users::Users(int n):name("비공개"),years(n){ 37 | 38 | } 39 | 40 | Users::Users(string names, int n):name(names),years(n){ 41 | 42 | } 43 | 44 | void Users::print(){ 45 | cout << "사용자명: " << name << ", 생성년도: " << years << endl; 46 | } -------------------------------------------------------------------------------- /011/Game_Information.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // 기본 생성자 6 | class info{ 7 | public: 8 | info(); // 기본 생성자 9 | void set(string); 10 | void set(int); 11 | void set(string, int); 12 | 13 | void print(); 14 | 15 | private: 16 | int age; 17 | string ID; 18 | }; 19 | 20 | 21 | // 생성자 오버로딩 22 | class Users{ 23 | public: 24 | Users(); 25 | Users(string); 26 | Users(int); 27 | Users(string, int); 28 | 29 | void print(); 30 | 31 | private: 32 | int years; 33 | string name; 34 | }; -------------------------------------------------------------------------------- /011/README.md: -------------------------------------------------------------------------------- 1 | # Constructor 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | Constructor는 생성자를 말합니다. 5 | 6 | 생성자는 말 그대로 오브젝트가 생성될 때 실행되는 함수로, 1번만 실행됩니다. 7 | 8 | 주로 멤버 변수 초기화에 사용됩니다. 9 | 10 | 생성자의 특징 몇가지를 우선 정의하고 가겠습니다. 11 | 12 | ### 생성자의 특징 13 | 14 | 1. 생성자의 이름은 클래스명과 동일 (대소문자까지) 15 | 2. public 클래스에서 선언 16 | 3. 결과형 리턴값을가지지 않음 17 | 18 | ## 기본 생성자 (Default constructor) 19 | 20 | 우선은 기본 생성자에 대해 먼저 알아봅시다. 21 | 22 | 기본 생성자는 매개변수가 없는 생성자입니다. 23 | 24 | 생성자를 만들지 않으면 자동으로 빈 기본 생성자가 클래스에서 만들어집니다. 25 | 26 | 지난번에 만들어둔 Game_Information 클래스를 이용하여 생성자를 만들어봅시다. 27 | 28 | 29 | 30 | ```cpp 31 | class info{ 32 | public: 33 | info(); // 기본 생성자 34 | void set(string); 35 | void set(int); 36 | void set(string, int); 37 | 38 | void print(); 39 | private: 40 | int age; 41 | string ID; 42 | }; 43 | ``` 44 | 클래스 안에 기본 생성자가 생긴것을 볼 수 있습니다. 45 | 기본 생성자이므로 ID는 빈 문자열로, age는 0으로 초기화 해주도록 합시다. (다른값도 가능) 46 | 47 | 48 | 49 | ```cpp 50 | . 51 | . 52 | . 53 | info::info(){ 54 | age = 0; 55 | ID = ""; 56 | } 57 | . 58 | . 59 | . 60 | ``` 61 | 62 | 이전 코드에서 위 코드를 추가해 주었습니다. 63 | 64 | 이렇게 기본 생성자 정의가 끝났다면 main함수에서 info 클래스를 선언할때 기본 생성자를 1번 부르게 되며, 우리가 설정한 값인 age = 0, ID = "" 형식으로 초기화가 될 것입니다. 65 | 66 | 67 | 68 | ```cpp 69 | . 70 | . 71 | . 72 | info A; 73 | A.print(); // 선언 후 바로 호출 (즉 기본 생성자 값 호출) 74 | . 75 | . 76 | . 77 | ``` 78 | 79 | > LOL 80 | 81 | > 아이디: , 나이: 0 82 | 83 | > 아이디: Hide on bush, 나이: 20 84 | 85 | > 아이디: Hide on bush, 나이: 17 86 | 87 | > 아이디: SKTT1 Faker, 나이: 17 88 | 89 | 초기화가 잘 되어있음을 볼 수 있습니다. 90 | 91 | 92 | ### 생성자를 다른 방법으로 정의 93 | 94 | 아까 생성자를 정의할 때 아래 코드처럼 정의를 했었습니다. 95 | 96 | 97 | 98 | ```cpp 99 | . 100 | . 101 | . 102 | info::info(){ 103 | age = 0; 104 | ID = ""; 105 | } 106 | . 107 | . 108 | . 109 | ``` 110 | 111 | 이번에는 다른 방법으로 정의해보도록 합시다. 112 | 113 | ```cpp 114 | . 115 | . 116 | . 117 | // 사용 형태 118 | // 클래스명::매개변수():멤버변수1(초기값),멤버변수2(초기값),멤버변수3(초기값)...멤버변수n(초기값) { 내용 } 119 | info::info():age(0),name(""){ 120 | } 121 | . 122 | . 123 | . 124 | ``` 125 | 126 | 위처럼 정의를 한다면 { } 안에 정의할 필요없이 바로 각 멤버 변수에 초기값을 할당할 수 있습니다. 127 | 128 | 129 | ## 생성자 오버로딩 130 | 131 | 바로 이전강의에서 오버로딩을 했었습니다. 132 | 133 | 이전 강의에서는 따로 선언을 한 다음, 클래스의 멤버 함수를 통해 매개변수의 값을 지정해주어야 했습니다. 134 | 135 | ```cpp 136 | info A; 137 | A.set("Hide on bush", 20); 138 | ``` 139 | 140 | 우리는 생성자 오버로딩을 통해서 간단하게 선언할 수 있도록 해봅시다. 141 | 142 | C++에서 추가된 선언 방식인 괄호를 사용할 수 있도록 만들 것입니다. 143 | 144 | ```cpp 145 | int i(10); 146 | double j(2.72); 147 | ``` 148 | 149 | Game_Information에서 Users 클래스로 만들것입니다. 150 | 151 | years는 계정 생성년도, name는 사용자명을 저장하는 변수가 되겠습니다. 152 | 153 | 154 | 155 | ```cpp 156 | // 생성자 오버로딩 157 | class Users{ 158 | public: 159 | Users(); 160 | Users(string); 161 | Users(int); 162 | Users(string, int); 163 | 164 | void print(); 165 | 166 | private: 167 | int years; 168 | string name; 169 | }; 170 | ``` 171 | 172 | 헤더파일의 Users 클래스를 보면 생성자가 오버로딩 되어있습니다. 173 | 174 | Users라는 동일한 변수가 4개 선언되어있는걸 볼 수 있습니다. 175 | 176 | 177 | 178 | ```cpp 179 | // 생성자 오버로딩 180 | Users::Users():name("비공개"),years(2020){ 181 | 182 | } 183 | 184 | Users::Users(string names):name(names),years(2020){ 185 | 186 | } 187 | 188 | Users::Users(int n):name("비공개"),years(n){ 189 | 190 | } 191 | 192 | Users::Users(string names, int n):name(names),years(n){ 193 | 194 | } 195 | 196 | void Users::print(){ 197 | cout << "사용자명: " << name << ", 생성년도: " << years << endl; 198 | } 199 | ``` 200 | 201 | 위의 코드를 보면 오버로딩된 생성자에 대해서 각각 초기화를 해주는 것을 볼 수 있습니다. 202 | 203 | ```cpp 204 | int main() 205 | { 206 | /* 207 | 생성자 오버로딩 208 | */ 209 | 210 | cout << "Users Data" << endl; 211 | 212 | Users A(); 213 | A.print(); 214 | 215 | Users B(2012); 216 | B.print(); 217 | 218 | Users C("이준원"); 219 | C.print(); 220 | 221 | Users D("이준원",2015); 222 | D.print(); 223 | } 224 | ``` 225 | 226 | > 사용자명: 비공개, 생성년도: 2020 227 | 228 | > 사용자명: 비공개, 생성년도: 2012 229 | 230 | > 사용자명: 이준원, 생성년도: 2020 231 | 232 | > 사용자명: 이준원, 생성년도: 2015 233 | 234 | 위처럼 각각의 생성자가 잘 불러진것을 확인할 수 있습니다. 235 | 236 | -------------------------------------------------------------------------------- /011/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Game_Information.h" 3 | using namespace std; 4 | 5 | int main(){ 6 | 7 | cout << "LOL" << endl; 8 | 9 | info A; 10 | 11 | A.print(); // 선언 후 바로 호출 (즉 기본 생성자 값 호출) 12 | 13 | A.set("Hide on bush", 20); 14 | A.print(); 15 | 16 | A.set(17); 17 | A.print(); 18 | 19 | A.set("SKTT1 Faker"); 20 | A.print(); 21 | 22 | 23 | /* 24 | 생성자 오버로딩 25 | */ 26 | 27 | cout << "Users Data" << endl; 28 | 29 | Users A(); 30 | A.print(); 31 | 32 | Users B(2012); 33 | B.print(); 34 | 35 | Users C("이준원"); 36 | C.print(); 37 | 38 | Users D("이준원",2015); 39 | D.print(); 40 | } -------------------------------------------------------------------------------- /012/Dot.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Dot.h" 3 | using namespace std; 4 | 5 | void Dot::set(int x1, int y1){ 6 | x = x1; 7 | y = y1; 8 | } 9 | 10 | void Dot::setX(int x1){ 11 | x = x1; 12 | } 13 | 14 | void Dot::setY(int y1){ 15 | y = y1; 16 | } 17 | 18 | int Dot::getX(){ 19 | return x; 20 | } 21 | 22 | int Dot::getY(){ 23 | return y; 24 | } -------------------------------------------------------------------------------- /012/Dot.h: -------------------------------------------------------------------------------- 1 | class Dot{ 2 | private: 3 | int x, y; 4 | public: 5 | void set(int, int); 6 | void setX(int); 7 | void setY(int); 8 | int getX(); 9 | int getY(); 10 | }; -------------------------------------------------------------------------------- /012/Location.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Location.h" 3 | using namespace std; 4 | 5 | void Location::setQ(int x1, int y1){ 6 | Q.setX(x1); 7 | Q.setY(y1); 8 | } 9 | 10 | void Location::setR(int x1, int y1){ 11 | R.setX(x1); 12 | R.setY(y1); 13 | } 14 | 15 | void Location::print(){ 16 | cout << "Q(" < 74 | 75 | ```cpp 76 | int main(){ 77 | 78 | cout << "9강에서 사용한 Location class" << endl; 79 | Location Two_dot; 80 | Two_dot.setQ(-1, 2); 81 | Two_dot.setR(-5, -5); 82 | Two_dot.print(); 83 | 84 | cout << "복사 생성자를 통한 복사" << endl; 85 | Location copy_dot(Two_dot); 86 | copy_dot.print(); 87 | 88 | cout << "복사 생성자를 통한 복사 2" << endl; 89 | Location copy_dot2 = Two_dot; 90 | copy_dot2.print(); 91 | 92 | return 0; 93 | } 94 | ``` 95 | 96 | > 9강에서 사용한 Location class 97 | 98 | > Q(-1, 2) 99 | 100 | > R(-5, -5) 101 | 102 | > 복사 생성자를 통한 복사 103 | 104 | > Q(-1, 2) 105 | 106 | > R(-5, -5) 107 | 108 | > 복사 생성자를 통한 복사 2 109 | 110 | > Q(-1, 2) 111 | 112 | > R(-5, -5) 113 | 114 | 115 | 위 코드에서 아래와 같은 부분을 볼 수 있습니다. 116 | 117 | ```cpp 118 | cout << "복사 생성자를 통한 복사" << endl; 119 | Location copy_dot(Two_dot); 120 | copy_dot.print(); 121 | 122 | cout << "복사 생성자를 통한 복사 2" << endl; 123 | Location copy_dot2 = Two_dot; 124 | copy_dot2.print(); 125 | ``` 126 | 127 | Two_dot라는 클래스 변수를 그대로 복사하여 copy_dot, copy_dot2라는 클래스 변수를 생성했습니다. 128 | 129 | 이런식으로 복사 생성자를 사용할 수 있습니다. 130 | 131 | 132 | 133 | ## 복사 대입 연산자 (Copy assignment operator) 134 | 135 | 생성시기에 대입연산자 '=' 를 이용해서 대입을 하면 복사 생성자가 호출이 되고 136 | 137 | 생성후 대입연산자 '=' 를 이용해서 대입을 하게되면 복사 대입연산자가 호출이 됩니다. 138 | 139 | 기본 생성자, 복사 생성자를 사용하지 않는 나머지의 일반적인 경우에서는 복사 대입 연산자를 사용하면 됩니다. 140 | 141 | ```cpp 142 | // 복사 생성자 143 | Users A("Hide on bush", 26); 144 | 145 | Users B1(p1); // 방법 1 146 | 147 | Users B2 = A; // 방법 2 148 | 149 | 150 | // 복사 대입 연산자 151 | Users A("Hide on bush", 26); 152 | 153 | Users B("Cpprhtn", 20); 154 | 155 | B = A; 156 | ``` -------------------------------------------------------------------------------- /012/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Location.h" 3 | using namespace std; 4 | 5 | int main(){ 6 | 7 | cout << "9강에서 사용한 Location class" << endl; 8 | Location Two_dot; 9 | Two_dot.setQ(-1, 2); 10 | Two_dot.setR(-5, -5); 11 | Two_dot.print(); 12 | 13 | cout << "복사 생성자를 통한 복사" << endl; 14 | Location copy_dot(Two_dot); 15 | copy_dot.print(); 16 | 17 | cout << "복사 생성자를 통한 복사 2" << endl; 18 | Location copy_dot2 = Two_dot; 19 | copy_dot2.print(); 20 | 21 | return 0; 22 | } -------------------------------------------------------------------------------- /013/Game_Information.cpp: -------------------------------------------------------------------------------- 1 | #include "Game_Information.h" 2 | 3 | Users::Users() :name("비공개"), years(2020) { 4 | 5 | } 6 | 7 | Users::Users(string names) : name(names), years(2020) { 8 | 9 | } 10 | 11 | Users::Users(int n) : name("비공개"), years(n) { 12 | 13 | } 14 | 15 | Users::Users(string names, int n) : name(names), years(n) { 16 | 17 | } 18 | 19 | void Users::print() { 20 | cout << "사용자명: " << name << ", 생성년도: " << years << endl; 21 | } 22 | 23 | // 소멸자 24 | Users::~Users() { 25 | cout << "User명이 \"" << name << "\"인 player가 계정을 탈퇴했습니다." << endl; 26 | } -------------------------------------------------------------------------------- /013/Game_Information.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class Users { 8 | public: 9 | Users(); 10 | Users(string); 11 | Users(int); 12 | Users(string, int); 13 | 14 | void print(); 15 | 16 | // 소멸자 17 | ~Users(); 18 | 19 | private: 20 | int years; 21 | string name; 22 | }; -------------------------------------------------------------------------------- /013/README.md: -------------------------------------------------------------------------------- 1 | # Destructor 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | 저번 강의에서는 생성자에 대해 다루었습니다. 5 | 6 | 이번에는 소멸자에 대한 설명을 하겠습니다. 7 | 8 | - 소멸자는 오브젝트가 사라질때 호출됩니다. 9 | - 여기서 오브젝트가 사라지는 경우는 크게 2가지입니다. 10 | - 프로그램이 끝났을 때. 11 | - 해당 scope를 벗어났을 때. 12 | 13 | 일반적으로 소멸자를 만들지 않으면, 컴파일러가 자동으로 만들어줍니다. 14 | 15 | 메모리 누수를 문법적으로 해결하는게 소멸자의 역할입니다. 16 | 17 | 소멸자를 선언하는 방법은 클래스명 앞에 ~(물결표시)를 붙여주는것입니다. (기본생성자 앞에 ~붙이는 것과 같다.) 18 | 19 | 이전에 만들었던 코드에서 한번 사용해보겠습니다. 20 | 21 | 22 | 23 | ```cpp 24 | class Users { 25 | public: 26 | Users(); 27 | Users(string); 28 | Users(int); 29 | Users(string, int); 30 | 31 | void print(); 32 | 33 | // 소멸자 34 | ~Users(); 35 | 36 | private: 37 | int years; 38 | string name; 39 | }; 40 | ``` 41 | 42 | 43 | 44 | 45 | ```cpp 46 | #include "Game_Information.h" 47 | 48 | /* 생략 */ 49 | 50 | // 소멸자 51 | Users::~Users() { 52 | 53 | } 54 | ``` 55 | 56 | 위의 코드처럼 소멸자를 추가할 수 있었습니다. 57 | 58 | 이번에는 소멸자가 언제 호출되는지를 확인 해보겠습니다. 59 | 60 | 61 | 62 | ```cpp 63 | #include "Game_Information.h" 64 | 65 | /* 생략 */ 66 | 67 | // 소멸자 68 | Users::~Users() { 69 | cout << "User명이 \"" << name << "\"인 player가 계정을 탈퇴했습니다." << endl; 70 | } 71 | ``` 72 | 73 | 74 | 75 | ```cpp 76 | #include 77 | #include "Game_Information.h" 78 | using namespace std; 79 | 80 | int main() { 81 | 82 | cout << "LOL\n" << endl; 83 | 84 | cout << "Users Data\n" << endl; 85 | 86 | Users A("이준원", 2015); 87 | { 88 | Users B("Cpprhtn", 2021); 89 | } 90 | 91 | cout << "\n프로그램이 종료됩니다.\n" << endl; 92 | 93 | } 94 | ``` 95 | 96 | 출력결과 97 | 98 | ![013-1](https://user-images.githubusercontent.com/63298243/111069136-07651200-850f-11eb-9068-bcd0e926a4aa.PNG) 99 | 100 | 101 | Game_information.cpp파일에서, 소멸자가 호출되면, 게임 계정을 탈퇴했다는 문구가 나오도록 수정해보았습니다. 102 | 103 | Users A 스코프 안에 Users B를 생성했습니다. 104 | 그리고 B의 스코프가 끝나므로 B의 소멸자가 먼저 호출되게 됩니다. 105 | 106 | A의 스코프는 아직 끝이난게 아니므로, "프로그램이 종료됩니다."라는 문구가 먼저 출력이 되며, 107 | 108 | 프로그램이 종료되며 A의 소멸자를 호출하게 됨을 알 수 있습니다. -------------------------------------------------------------------------------- /013/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Game_Information.h" 3 | using namespace std; 4 | 5 | int main() { 6 | 7 | cout << "LOL\n" << endl; 8 | 9 | cout << "Users Data\n" << endl; 10 | 11 | Users A("이준원", 2015); 12 | { 13 | Users B("Cpprhtn", 2021); 14 | } 15 | 16 | cout << "\n프로그램이 종료됩니다.\n" << endl; 17 | 18 | } -------------------------------------------------------------------------------- /014/README.md: -------------------------------------------------------------------------------- 1 | # dynamic allocating 2 | 반갑습니다. Cpprhtn입니다. 3 | 4 | 저번 강의에서는 생성자와 소멸자에 대해 다루었습니다. 5 | 6 | 이번에는 동적 할당에 대한 설명을 하겠습니다. 7 | 8 | ### 동적 할당(dynamic allocation) 9 | 10 | [동적 메모리 할당 - 위키백과](https://ko.wikipedia.org/wiki/%EB%8F%99%EC%A0%81_%EB%A9%94%EB%AA%A8%EB%A6%AC_%ED%95%A0%EB%8B%B9) 참고 11 | 12 | 동적 할당은 실행 시간 동안 사용할 메모리 공간을 할당하는 것을 의미합니다 13 | 14 | C언어에서는 malloc(), free()함수를 사용했었습니다. 15 | 16 | C++에서도 malloc(), free()함수를 사용하여 메모리의 동적 할당 및 해제를 할 수 있습니다. 17 | 18 | 하지만 C++에서는 메모리의 동적 할당 및 해제를 위한 더욱 효과적인 방법을 new와 delete 연산자를 통해 제공합니다. 19 | 20 | new와 delete 연산자는 내부적으로 malloc()과 free()와 유사한 함수를 사용하여 메모리 맵상의 힙영역으로부터 저장공간을 할당합니다. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Lee_JunWon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cpp_Study 2 | 3 | C언어의 기본적인 내용을 안다는 전제하에 강좌글을 쓸 예정 4 | 5 | |ID|Title|Description| 6 | |:---:|:---|:---| 7 | |000|[C에서 C++로 넘어가며](./000/README.md)|C에서 C++로 넘어가며| 8 | |001|[입출력 익히기](./001/README.md)|입출력에 대한 설명| 9 | |002|[namespace](./002/README.md)|namespace에 대한 개념| 10 | |003|[pointer](./003/README.md)|pointer에 대한 개념| 11 | |004|[pointer2](./004/README.md)|smart pointer에 대한 설명| 12 | |005|[reference](./005/README.md)|reference에 대한 개념| 13 | |006|[string](./006/README.md)|string에 대한 개념| 14 | |007|[class](./007/README.md)|class에 대한 개념| 15 | |008|[class2](./008/README.md)|class - private| 16 | |009|[code division](./009/README.md)|코드 분할 방법 설명| 17 | |010|[overloading](./010/README.md)|오버로딩에 대한 설명| 18 | |011|[constructor](./011/README.md)|생성자에 대한 설명| 19 | |012|[constructor2](./012/README.md)|생성자에 대한 설명| 20 | |013|[destructor](./013/README.md)|소멸자에 대한 설명| 21 | |014|[dynamic allocating](./014/README.md)|동적 할당에 대한 설명| 22 | -------------------------------------------------------------------------------- /img/013-1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cpprhtn/Cpp_Study/8f43ed704ce535fa0e94d9c5b3b0faf63dbf44ea/img/013-1.PNG --------------------------------------------------------------------------------