1. 어셈블리 코드 확인 하는 방법
[Compiler Explorer] godgolt.org
x63 msvc v19.latest : MS Visual Studio Compiler
2. namespace 개념
하나의 프로젝트를 여러명의 개발자가 같이 개발할 때, 동일한 요소이름을 사용할 수 있도록 하는 영역
namespcae 문법을 사용하면 관련된 코드를 묶어서 관리할 수 있다. (함수, 구조체, 전역 변수)
2.1 namespace 요소에 접근하는 방법
- qualified name (완전한 이름) *권장됨
Myspace::myFunc(); //사용
-using declaration (선언)
: namespace:: 이름 없이 '특정' 요소 사용가능
using Myspace::myFunc(); //선언, main() 내부, 전역 공간 모두 선언가능
myFunc(); //사용
-using directive (지시어)
: namcspace:: 이름 없이 namespace 안의 '모든' 요소를 사용가능
using namespace Myspace; //선언
myFunc(); //사용
2.2. global namespace
: 특정 namespace 에 포함되지 않은 공간, 아래 복잡한 경우의 수는 qulified name (완전한 이름) 을 사용하면 문제 발생하지 않는다.
void myFunc() { } //선언, main부 밖 전역 공간.
::myFunc(); //사용, global namespace 검색, 없으면 에러
myFunc(); //사용, 열려있는 namespace 검색, 없으면 global namespace 검색
2.3. std namespace
: C++ 의 표준함수는 "std" namespace 안에 있다.
: C++ 표준내부에는 수많은 요소들이 있으므로, 충돌방지를 위해 사용을 지양한다. '완전한 이름'을 사용할 것.
using namespace std; //선언
int n1 = max(10, 20); // 사용
2.4. 중첩 (nested) namespace
: namespace 는 중첩(nested) 될 수 있다.
namespace Myspace
{
namespace Myroom
{}
}
2.5. namespace alias
: namespace 변수화
namespace Myns = std::filesystem; //선언
Myns::copyfile(); //사용
3. 헤더 파일
: C++ 표준 헤더파일 이름에는 .h 가 붙어있지 않다. ex) #include <algorithm>
: 사용자가 만든 헤더는 .h 을 붙인다.
: C 스타일의 헤더는 C++ 버전이 별도로 존재한다. .h 를 떼고 앞에 c를 붙인다. ex) <stdio.h> -> <cstdio>
: C++ 표준 헤더의 모든 요소는 std namespace 안에 모두 제공된다.
: 일부 라이브러리들은 중첩되어 있다. ex) std::filesystem (파일관련), std::chrono (날짜/시간)
3.1. namespace 와 파일 분할
: 여러파일에 동일 namespace 사용가능
: 헤더파일에 선언, 구현은 소스(.cpp) 파일에 한다.
// [main.cpp]
#include "Video1.h"
#include "Video2.h"
int main()
{
Video::init();
Video::start();
}
// [Video1.h]
namespace Video
{
void init();
}
// [Video1.cpp]
namespace Video
{
void init()
{
}
}
// [Video2.h]
namespace Video
{
void start();
}
// [Video2.cpp]
namespace Video
{
void start()
{
}
}
4. auto, decltype
- auto
: 변수 선언시, 우변의 표현식을 조사해서 컴파일러가 변수의 타입을 결정
- deltype
: () 안의 표현식으로 타입을 결정
int x[5] = {1,2,3,4,5};
auto n = x[0]; // int n = x[0]
decltype(n) n1; // int n1
auto arr = x; // int* arr = x;
decltype(x) arr1; // error
5. typedef, using
- typedef
: type 에 대한 별칭
- using
: type 에 대한 별칭 + template 에 대한 별칭
typedef int MYTYPE;
using MYTYPE = int;
MYTYPE n;
6. 일관된 초기화 (Uniform Initialization)
: C++11 이후 모든 종류의 변수를 동일한 방법으로 초기화 할 수 있도록 함.
: 중괄호 초기화 (brace-init) 이라고도 부름
-복사 초기화 (Copy Init.)
: = 사용 초기화
int n = {3};
-직접 초기화 (Direct Init.)
: = 없이 초기화
int n{3};
6.1. prevent narrow
: 일관된 초기화시 타입보다 초기화 데이터가 클경우, 데이터 손실시 error
: 안정화 가능
int n1 = 3.4 // ok
int n2 = {3.4} // error
int n3{3.4} // error
7. struct 와 structure binding
struct Point
{
int x = 1;
int y{2};
}
Point foo()
{
Point p = {1,2}; //배열
return p;
}
int main()
{
struct Point pt1; // C방식 구조체 선언
Point pt1 = {3,4};
// Structure Binding : 구조체 변수 가져오기 C++17
auto [a,b] = pt1;
//int a = pt1.x;
//int b = pt1.y;
int arr[3] = {1,2,3};
auto [a,b,c] = arr;
//int a = arr[0]; int b = arr[1]; int c = arr[2];
}
8. 문자열
: 문자열 처리 - char 배열을 사용해야 한다. =,== 연산자 사용불가
: <string> 을 사용하면 변수처럼 +,==,= 등의 연산자 사용가능하다.
: 주의 <cstring> 은 C<string.h> 의 C++ 버전, <string> 은 std::string 을 사용하기 위한 헤더
#include <cstring>
#include <string>
char s1[] = "abcd";
char s2[5];
strcpy_s(s2,s1);
std::string s1 = "wxyz";
std::string s2;
s2 = s1;
9. 디폴트 파라미터
: 함수 호출시 인자 미전달시 "미리 지정된 인자 값"을 사용한다.
void myFunc(int a, int b = 0, int c = 0)
{
a = b + c;
}
int main()
{
myFunc(1,2,3);
myFunc(1,2); //myFunc(1,2,0)
myFunc(1); //myFunc(1,0,0)
}
: * 마지막 인자 부터 차례대로 디폴트 값을 지정해야 한다.
void myFunc(int a = 0, int b = 0, int c = 0); // ok
void myFunc(int a , int b = 0, int c = 0); // ok
void myFunc(int a = 0, int b , int c = 0); // error
void myFunc(int a = 0, int b = 0, int c ); // error
: * 함수 선언/구현부로 분리 할 때는 "함수 선언부"에만 디폴트 인자를 표기해야 한다.
void myFunc(int a = 0, int b = 0, int c = 0){} // error
void myFunc(int a /*= 0*/, int b /*= 0*/, int c /*= 0*/){} // ok
10. Fuction Overloading
: 함수 이름이 같아도, 인자 개수,타입이 다르면 "동일한 이름의 함수를 여러개 만들 수 있다."
int sqr(int a)
{
return a * a;
}
double sqr(double a)
{
return a * a;
}
int main()
{
auto ret1 = sqr(3);
auto ret2 = sqr(3.14);
}
: * 인자 모호함은 에러 발생 (리턴차입차이, 디폴트인자, 타입구분안되는 경우)
void f1(int a) {return 1;}
void f1(int a) {return 0;} //error
void f2(int a) {}
void f2(int a, int b = 0) {}
f2(1); // ambiguos error
void f3(char a) {}
void f3(short a) {}
f3('1'); // error - int => char/short 가능
: 원리 - 컴파일러가 인수를 보고, 함수의 이름을 변경한다. name mangling (규칙은 컴파일러마다 다르다.)
int sqr(int a) -> sqr_i
int sqr(double a) -> sqr_d
/*
* 문제점
1. int type 변수 4개를 사용하여 코드가 복잡해진다.
: 사각형 타입이 없으므로, 사각형 한 개를 int 변수 4개로 표현하기 때문임
-> struct : 사각형 타입을 만든다. [struct Rect]
*
*/
#include <iostream>
int getRectArea(int x1, int y1, int x2, int y2)
{
return (x2 - x1) * (y2 - y1);
}
void drawRect(int x1, int y1, int x2, int y2)
{
std::cout << "DRAW RECT." << std::endl;
}
int main()
{
int n = getRectArea(1, 1, 10, 10);
drawRect(1, 1, 10, 10);
}
/*
* 해결점
1. int type 변수 4개를 사용하여 코드가 복잡해진다.
-> 사각형 타입이 없으므로, 사각형 한 개를 int 변수 4개로 표현하기 때문임
-> 사각형 타입을 만든다. : 구조체 struct
* 문제점
1. struct 에 Call by Value 로 인수를 전달하여 "복사본 오버헤드"가 생긴다.
: 인자로 전달된 변수를 수정하지 않겠다는 약속이 있다.
: 그런데, 구조체 타입을 함수에서 인자로 전달될 때 Rect type data 크기만큼의 "복사본 오버헤드가 생긴다."
-> Ref. : 함수에서 복사하지 않고 참조로 인자를 받아 사용한다. [Rect& r]
-> const Refr. : 참조로 받을때 함수내에서 수정되지 않도록 한다. [const Rect& r]
* 사용자 정의 타입을 인자로 전달할 때는 call by value 가 아닌, ref. 로 전달한다. 값 변경하지 않을 것이면 const ref. 로 전달.
*/
#include <iostream>
struct Rect // 필요한 사용자 정의 타입 설계
{
int left; // x1
int top; // y1
int right; // x2
int bottom; // y2
};
int getRectArea(Rect r)
{
return (r.right - r.left) * (r.bottom - r.top);
}
void drawRect(Rect r)
{
std::cout << "DRAW RECT." << std::endl;
}
int main()
{
Rect rc = { 1, 1, 10, 10 };
int n = getRectArea(rc);
drawRect(rc);
}
/*
* 해결점
1. int type 변수 4개를 사용하여 코드가 복잡해진다.
-> 사각형 타입이 없으므로, 사각형 한 개를 int 변수 4개로 표현하기 때문임
-> 사각형 타입을 만든다. : 구조체 struct
2. struct 에 Call by Value 로 인수를 전달하여 "복사본 오버헤드"가 생긴다.
-> 인자로 전달된 변수를 수정하지 않겠다는 약속이 있다.
-> 그런데, 구조체 타입을 함수에서 인자로 전달될 때 Rect type data 크기만큼의 "복사본 오버헤드가 생긴다."
-> 함수에서 복사하지 않고 참조로 인자를 받아 사용한다. : Reference - Rect& r
-> 참조로 받을때 함수내에서 수정되지 않도록 : Const Refr. 로 받는다 - const Rect& r
-> * 사용자 정의 타입을 인자로 전달할 때는 call by value 가 아닌, ref. 로 전달한다. 값 변경하지 않을 것이면 const ref. 로 전달.
* 문제점
1. 상태를 나타내는 "데이터(Rect)"와 상태를 조작하는 "함수(getRectArea)" 를 분리되어 있다.
: 데이터를 항상 함수의 인자로 전달해야 한다.
: 사각형 관련 모든 함수는 인자로 Rect 를 받아야 한다.
-> 구조체 안에 함수를 넣는다. 함수는 구조체 변수를 인자로 받지 않고 바로 사용할 수 있게된다.
-> 함수들은 Rect 구조체 내부에 있는 것이므로, 함수명에 Rect 를 생략한다.
* 데이터와 함수를 묶어서 타입을 설계하면
* 보다 안전하고, 사용하기 쉬운 타입을 설계할 수 있다.
*
* 구조체 데이터 : member data, field
* 구조체 함수 : member function, method
*/
#include <iostream>
struct Rect
{
int left; // x1
int top; // y1
int right; // x2
int bottom; // y2
};
int getRectArea(const Rect& r) // 사용자 정의 타입 인자는 참조로 전달받는다. const ref.
{
return (r.right - r.left) * (r.bottom - r.top);
}
void drawRect(const Rect& r)
{
std::cout << "DRAW RECT." << std::endl;
}
int main()
{
Rect rc = { 1, 1, 10, 10 };
int n = getRectArea(rc);
drawRect(rc);
}
/*
* 해결점
1. 사용자 지정 타입을 만든다. : 구조체 struct
2. 사용자 정의 타입을 인자로 전달할 때는 call by value 가 아닌, ref. 로 전달한다. 값 변경하지 않을 것이면 const ref. 로 전달.
3. 구조체 안에 함수를 넣는다. 함수는 구조체 변수를 인자로 받지 않고 바로 사용할 수 있게된다.
* 문제점
1. 멤버 데이터를 외부에서 직접 접근하면 객체가 잘못된 상태가 될 수 있다.
: 멤버 데이터는 외부의 잘못된 사용으로 부터 보호하는 것이 안전하다.
-> 접근 지정자 : private / public / protected
- private : 멤버 함수에서만 접근 가능
- public : 모든 함수에서 접근 가능
- protected : 멤버 함수와 파생 클래스 멤버 함수에서 접근 가능. 상속 참고.
* 캡슐화 (Encapsulation)
- 멤버 데이터는 private 영역에 두어, 외부의 오용으로 부터 보호한다.
- 멤버 데이터의 변경은 잘 정의된 규칙을 가진 멤버 함수를 통해서만 변경 가능하게 한다.
*/
#include <iostream>
struct Rect
{
int left; // x1
int top; // y1
int right; // x2
int bottom; // y2
int getArea() // 구조체 변수를 바로 사용할 수 있다. 이름의 Rect 생략
{
return (right - left) * (bottom - top);
}
void draw()
{
std::cout << "DRAW RECT." << std::endl;
}
};
int main()
{
Rect rc = { 1, 1, 10, 10 };
// int n = getRectArea(rc); // 사각형 rc 의 좌표를 던져줄테니 면적을 구해달라.
int n = rc.getArea(); // 사각형 rc 의 면적을 구해달라.
rc.draw(); // compile - draw(&rc)
}
/*
* 해결점
1. int type 변수 4개를 사용하여 코드가 복잡해진다.
-> 사각형 타입이 없으므로, 사각형 한 개를 int 변수 4개로 표현하기 때문임
-> 사각형 타입을 만든다. : 구조체 struct
2. struct 에 Call by Value 로 인수를 전달하여 "복사본 오버헤드"가 생긴다.
-> 인자로 전달된 변수를 수정하지 않겠다는 약속이 있다.
-> 그런데, 구조체 타입을 함수에서 인자로 전달될 때 Rect type data 크기만큼의 "복사본 오버헤드가 생긴다."
-> 함수에서 복사하지 않고 참조로 인자를 받아 사용한다. : Reference - Rect& r
-> 참조로 받을때 함수내에서 수정되지 않도록 : Const Refr. 로 받는다 - const Rect& r
-> * 사용자 정의 타입을 인자로 전달할 때는 call by value 가 아닌, ref. 로 전달한다. 값 변경하지 않을 것이면 const ref. 로 전달.
3. 상태를 나타내는 "데이터(Rect)"와 상태를 조작하는 "함수(getRectArea)" 를 분리되어 있다.
: 데이터를 항상 함수의 인자로 전달해야 한다.
: 사각형 관련 모든 함수는 인자로 Rect 를 받아야 한다.
-> 구조체 안에 함수를 넣는다. 함수는 구조체 변수를 인자로 받지 않고 바로 사용할 수 있게된다.
-> 함수들은 Rect 구조체 내부에 있는 것이므로, 함수명에 Rect 를 생략한다.
* 데이터와 함수를 묶어서 타입을 설계하면
* 보다 안전하고, 사용하기 쉬운 타입을 설계할 수 있다.
*
* 구조체 데이터 : member data, field
* 구조체 함수 : member function, method
4. 멤버 데이터를 외부에서 직접 접근하면 객체가 잘못된 상태가 될 수 있다.
: 멤버 데이터는 외부의 잘못된 사용으로 부터 보호하는 것이 안전하다.
-> 접근 지정자 : private / public / protected
- private : 멤버 함수에서만 접근 가능
- public : 모든 함수에서 접근 가능
- protected : 멤버 함수와 파생 클래스 멤버 함수에서 접근 가능. 상속 참고.
* 캡슐화 (Encapsulation)
- 멤버 데이터는 private 영역에 두어, 외부의 오용으로 부터 보호한다.
- 멤버 데이터의 변경은 잘 정의된 규칙을 가진 멤버 함수를 통해서만 변경 가능하게 한다.
* 문제점
1. struct vs class
- struct : 접근 지정자 생략시 디폴트가 public. "모두 공개하고, 선택적으로 보호한다."
- class : 접근 지정자 생략시 디폴트가 private. "모두 보호하고, 선택적으로 공개한다."
* 객체 지향에서는 class 의 사용이 더 올바르다.
* C++ 에서 struct, class 의 차이는 위가 전부다.
*/
#include <iostream>
#include <string>
struct Person
{
private: // 변수 접근 방지
std::string name;
int age;
public: // 모든 함수에서 접근 가능. 외부(main)에서 접근가능
void setAge(int value)
{
if ( value >= 1 && value < 150 )
age = value;
}
};
int main()
{
Person p;
// p.age = -10 //잘못된 사용, 바로 접근시 방어할 방법이 없다.
p.setAge(-10);
}
/*
* 해결점
1. int type 변수 4개를 사용하여 코드가 복잡해진다.
-> 사각형 타입이 없으므로, 사각형 한 개를 int 변수 4개로 표현하기 때문임
-> 사각형 타입을 만든다. : 구조체 struct
2. struct 에 Call by Value 로 인수를 전달하여 "복사본 오버헤드"가 생긴다.
-> 인자로 전달된 변수를 수정하지 않겠다는 약속이 있다.
-> 그런데, 구조체 타입을 함수에서 인자로 전달될 때 Rect type data 크기만큼의 "복사본 오버헤드가 생긴다."
-> 함수에서 복사하지 않고 참조로 인자를 받아 사용한다. : Reference - Rect& r
-> 참조로 받을때 함수내에서 수정되지 않도록 : Const Refr. 로 받는다 - const Rect& r
-> * 사용자 정의 타입을 인자로 전달할 때는 call by value 가 아닌, ref. 로 전달한다. 값 변경하지 않을 것이면 const ref. 로 전달.
3. 상태를 나타내는 "데이터(Rect)"와 상태를 조작하는 "함수(getRectArea)" 를 분리되어 있다.
: 데이터를 항상 함수의 인자로 전달해야 한다.
: 사각형 관련 모든 함수는 인자로 Rect 를 받아야 한다.
-> 구조체 안에 함수를 넣는다. 함수는 구조체 변수를 인자로 받지 않고 바로 사용할 수 있게된다.
-> 함수들은 Rect 구조체 내부에 있는 것이므로, 함수명에 Rect 를 생략한다.
* 데이터와 함수를 묶어서 타입을 설계하면
* 보다 안전하고, 사용하기 쉬운 타입을 설계할 수 있다.
*
* 구조체 데이터 : member data, field
* 구조체 함수 : member function, method
4. 멤버 데이터를 외부에서 직접 접근하면 객체가 잘못된 상태가 될 수 있다.
: 멤버 데이터는 외부의 잘못된 사용으로 부터 보호하는 것이 안전하다.
-> 접근 지정자 : private / public / protected
- private : 멤버 함수에서만 접근 가능
- public : 모든 함수에서 접근 가능
- protected : 멤버 함수와 파생 클래스 멤버 함수에서 접근 가능. 상속 참고.
* 캡슐화 (Encapsulation)
- 멤버 데이터는 private 영역에 두어, 외부의 오용으로 부터 보호한다.
- 멤버 데이터의 변경은 잘 정의된 규칙을 가진 멤버 함수를 통해서만 변경 가능하게 한다.
5. struct vs class
- struct : 접근 지정자 생략시 디폴트가 public. "모두 공개하고, 선택적으로 보호한다."
- class : 접근 지정자 생략시 디폴트가 private. "모두 보호하고, 선택적으로 공개한다."
* 객체 지향에서는 class 의 사용이 더 올바르다.
* C++ 에서 struct, class 의 차이는 위가 전부다.
* 문제점
1. 구조체 생성시 데이터 초기화할 수 없다.
-> 생성자(constructor) 와 소멸자(destructor)
1.1. 생성자
- 클래스이름() 모양의 함수
- 객체 생성시 자동 호출
- 반환 타입을 표기하지 않고, 반환할 수 없다.
- 인자가 없어도, 있어도 된다.
- 2개 이상 만들 수 있다.
- 생성자가 없으면 컴파일러가 디폴트 생성자를 제공한다.
1.2. 소멸자
- ~클래스이름() 모양의 함수
- 객체 파괴시 자동 호출
*/
#include <iostream>
#include <string>
class Person // public -> class
{
//private: // class는 private 가 디폴트.
std::string name;
int age;
public:
void setAge(int value)
{
if (value >= 1 && value < 150)
age = value;
}
};
int main()
{
Person p;
p.setAge(-10);
}
/*
* 해결점
1. int type 변수 4개를 사용하여 코드가 복잡해진다.
-> 사각형 타입이 없으므로, 사각형 한 개를 int 변수 4개로 표현하기 때문임
-> 사각형 타입을 만든다. : 구조체 struct
2. struct 에 Call by Value 로 인수를 전달하여 "복사본 오버헤드"가 생긴다.
-> 인자로 전달된 변수를 수정하지 않겠다는 약속이 있다.
-> 그런데, 구조체 타입을 함수에서 인자로 전달될 때 Rect type data 크기만큼의 "복사본 오버헤드가 생긴다."
-> 함수에서 복사하지 않고 참조로 인자를 받아 사용한다. : Reference - Rect& r
-> 참조로 받을때 함수내에서 수정되지 않도록 : Const Refr. 로 받는다 - const Rect& r
-> * 사용자 정의 타입을 인자로 전달할 때는 call by value 가 아닌, ref. 로 전달한다. 값 변경하지 않을 것이면 const ref. 로 전달.
3. 상태를 나타내는 "데이터(Rect)"와 상태를 조작하는 "함수(getRectArea)" 를 분리되어 있다.
: 데이터를 항상 함수의 인자로 전달해야 한다.
: 사각형 관련 모든 함수는 인자로 Rect 를 받아야 한다.
-> 구조체 안에 함수를 넣는다. 함수는 구조체 변수를 인자로 받지 않고 바로 사용할 수 있게된다.
-> 함수들은 Rect 구조체 내부에 있는 것이므로, 함수명에 Rect 를 생략한다.
* 데이터와 함수를 묶어서 타입을 설계하면
* 보다 안전하고, 사용하기 쉬운 타입을 설계할 수 있다.
*
* 구조체 데이터 : member data, field
* 구조체 함수 : member function, method
4. 멤버 데이터를 외부에서 직접 접근하면 객체가 잘못된 상태가 될 수 있다.
: 멤버 데이터는 외부의 잘못된 사용으로 부터 보호하는 것이 안전하다.
-> 접근 지정자 : private / public / protected
- private : 멤버 함수에서만 접근 가능
- public : 모든 함수에서 접근 가능
- protected : 멤버 함수와 파생 클래스 멤버 함수에서 접근 가능. 상속 참고.
* 캡슐화 (Encapsulation)
- 멤버 데이터는 private 영역에 두어, 외부의 오용으로 부터 보호한다.
- 멤버 데이터의 변경은 잘 정의된 규칙을 가진 멤버 함수를 통해서만 변경 가능하게 한다.
5. struct vs class
- struct : 접근 지정자 생략시 디폴트가 public. "모두 공개하고, 선택적으로 보호한다."
- class : 접근 지정자 생략시 디폴트가 private. "모두 보호하고, 선택적으로 공개한다."
* 객체 지향에서는 class 의 사용이 더 올바르다.
* C++ 에서 struct, class 의 차이는 위가 전부다.
6. 구조체 생성시 데이터 초기화할 수 없다.
-> 생성자(constructor) 와 소멸자(destructor)
1.1. 생성자
- 클래스이름() 모양의 함수
- 객체 생성시 자동 호출
- 반환 타입을 표기하지 않고, 반환할 수 없다.
- 인자가 없어도, 있어도 된다.
- 2개 이상 만들 수 있다.
- 생성자가 없으면 컴파일러가 디폴트 생성자를 제공한다.
1.2. 소멸자
- ~클래스이름() 모양의 함수
- 객체 파괴시 자동 호출
* 문제점
1. 클래스 선언에 멤버 함수의 '구현'을 포함
-> 멤버 함수를 선언과 구현으로 분리한 후, "헤더파일(.h)과 소스파일(.cpp)" 로 분리해서 작성
* 템플릿 사용시 반드시 헤더 파일에 멤버 함수 구현부도 있어야 한다. (linkage)
*/
#include <iostream>
#include <string>
class Person
{
std::string name;
int age;
public:
// void init() {}
Person() // 생성자, init.
{
name = 'kim';
age = 20;
}
Person(std::string str, int numb) //생성자2
{
name = str;
age = numb;
}
~Person() // 소멸자
{
std::cout << "Destructor" << std::endl;
}
void setAge(int value)
{
if (value >= 1 && value < 150)
age = value;
}
};
int main()
{
Person p; //생성자 호출
Person p2("hong", 18); //생성자2 호출
}// 소멸자 호출
/*
* 해결점
1. int type 변수 4개를 사용하여 코드가 복잡해진다.
-> 사각형 타입이 없으므로, 사각형 한 개를 int 변수 4개로 표현하기 때문임
-> 사각형 타입을 만든다. : 구조체 struct
2. struct 에 Call by Value 로 인수를 전달하여 "복사본 오버헤드"가 생긴다.
-> 인자로 전달된 변수를 수정하지 않겠다는 약속이 있다.
-> 그런데, 구조체 타입을 함수에서 인자로 전달될 때 Rect type data 크기만큼의 "복사본 오버헤드가 생긴다."
-> 함수에서 복사하지 않고 참조로 인자를 받아 사용한다. : Reference - Rect& r
-> 참조로 받을때 함수내에서 수정되지 않도록 : Const Refr. 로 받는다 - const Rect& r
-> * 사용자 정의 타입을 인자로 전달할 때는 call by value 가 아닌, ref. 로 전달한다. 값 변경하지 않을 것이면 const ref. 로 전달.
3. 상태를 나타내는 "데이터(Rect)"와 상태를 조작하는 "함수(getRectArea)" 를 분리되어 있다.
: 데이터를 항상 함수의 인자로 전달해야 한다.
: 사각형 관련 모든 함수는 인자로 Rect 를 받아야 한다.
-> 구조체 안에 함수를 넣는다. 함수는 구조체 변수를 인자로 받지 않고 바로 사용할 수 있게된다.
-> 함수들은 Rect 구조체 내부에 있는 것이므로, 함수명에 Rect 를 생략한다.
* 데이터와 함수를 묶어서 타입을 설계하면
* 보다 안전하고, 사용하기 쉬운 타입을 설계할 수 있다.
*
* 구조체 데이터 : member data, field
* 구조체 함수 : member function, method
4. 멤버 데이터를 외부에서 직접 접근하면 객체가 잘못된 상태가 될 수 있다.
: 멤버 데이터는 외부의 잘못된 사용으로 부터 보호하는 것이 안전하다.
-> 접근 지정자 : private / public / protected
- private : 멤버 함수에서만 접근 가능
- public : 모든 함수에서 접근 가능
- protected : 멤버 함수와 파생 클래스 멤버 함수에서 접근 가능. 상속 참고.
* 캡슐화 (Encapsulation)
- 멤버 데이터는 private 영역에 두어, 외부의 오용으로 부터 보호한다.
- 멤버 데이터의 변경은 잘 정의된 규칙을 가진 멤버 함수를 통해서만 변경 가능하게 한다.
5. struct vs class
- struct : 접근 지정자 생략시 디폴트가 public. "모두 공개하고, 선택적으로 보호한다."
- class : 접근 지정자 생략시 디폴트가 private. "모두 보호하고, 선택적으로 공개한다."
* 객체 지향에서는 class 의 사용이 더 올바르다.
* C++ 에서 struct, class 의 차이는 위가 전부다.
6. 구조체 생성시 데이터 초기화할 수 없다.
-> 생성자(constructor) 와 소멸자(destructor)
1.1. 생성자
- 클래스이름() 모양의 함수
- 객체 생성시 자동 호출
- 반환 타입을 표기하지 않고, 반환할 수 없다.
- 인자가 없어도, 있어도 된다.
- 2개 이상 만들 수 있다.
- 생성자가 없으면 컴파일러가 디폴트 생성자를 제공한다.
1.2. 소멸자
- ~클래스이름() 모양의 함수
- 객체 파괴시 자동 호출
7. 클래스 선언에 멤버 함수의 '구현'을 포함
-> 멤버 함수를 선언과 구현으로 분리한 후, "헤더파일(.h)과 소스파일(.cpp)" 로 분리해서 작성
* 템플릿 사용시 반드시 헤더 파일에 멤버 함수 구현부도 있어야 한다. (linkage)
* 문제점
*/
#include <iostream>
#include <string>
//===============================================================================================
//선언부 [Person.h]
// #pragma once //header include 2번 되는 것 방지.
class Person
{
std::string name;
int age;
public:
Person(); // class 내부에 선언만 남긴다.
Person(std::string str, int numb);
~Person();
void setAge(int value);
};
//===============================================================================================
// 구현부 [Person.cpp]
Person::Person() //#include "Person.h" //header file include
{
name = 'kim';
age = 20;
}
Person::Person(std::string str, int numb)
{
name = str;
age = numb;
}
Person::~Person()
{
std::cout << "Destructor" << std::endl;
}
void Person::setAge(int value)
{
if (value >= 1 && value < 150)
age = value;
}
//===============================================================================================
// 메인부 [main.cpp]
//#include "Person.h" //class header file include
int main()
{
Person p;
Person p2("hong", 18);
}
//===============================================================================================