1. 네임스페이스 (namespace)
네임스페이스는 라이브러리 간 충돌(conflict)을 방지하기 위해 사용된다. 어떤 라이브러리와 네임스페이스를 사용하는지 명시적으로 선언할 수 있다.
예를 들어, C++ 표준 라이브러리의 함수들은 std 네임스페이스에 정의되어 있다. 이를 사용하려면 다음과 같이 선언한다
Python의 모듈(module)과 유사한 역할을 한다.
2. main 함수
main() 함수는 프로그램의 시작점을 정의한다. 모든 C++ 프로그램은 main() 함수로 시작된다.
C++에서 main()은 반드시 반환값이 있어야 하므로 일반적으로 return 0;으로 종료한다.
3. 변수의 타입 선언
C++은 정적 타입(static type) 언어로, 변수나 함수를 사용하기 전에 데이터 타입을 명시적으로 선언해야 한다.
4. 입출력 (cin, cout)
cout은 콘솔 출력에 사용되며, 기본적으로 유효 숫자 6자리까지만 출력한다. 이를 초과하는 숫자는 소실된다.
cin은 콘솔 입력에 사용된다.
5. 논리 연산자의 단축 평가
C++에서 &&와 || 논리 연산자는 그 전에 결과가 결정나면, 이후를 check하지 않는다.
- &&: 왼쪽 피연산자가 false이면 오른쪽을 평가하지 않는다.
- ||: 왼쪽 피연산자가 true이면 오른쪽을 평가하지 않는다.
6. inline 함수
inline 함수는 컴파일러가 컴파일 타임에 해당 함수의 코드를 **스택이 아닌 코드 영역(code section)**에 직접 삽입하도록 지시한다. 이 방식은 함수 호출의 오버헤드를 줄여 실행 속도를 높인다.
7. 변수의 스코프와 생명주기
- Local 변수:
{} 내부에서만 유효하며, 함수가 종료되면 메모리에서 사라진다. - Global 변수:
프로그램 전체에서 유효하며, 프로그램이 종료될 때 메모리에서 사라진다. - Static 변수:
{} 내부에서만 유효하지만, 프로그램이 종료될 때까지 메모리에 남아 있다.
Static 변수는 단 한 번만 초기화된다. 아래 예시에서 static int가 아닌 그냥 int라면, example()을 수행할 때마다 count가 0으로 초기화될 것이다.
void example() {
static int count = 0; // 프로그램 종료 시까지 메모리에 유지
count++;
cout << count << endl;
}
8. Call by Value와 Call by Reference
- Call by Value:
값을 복사하여 전달하므로 함수 내부에서 원본 값이 변경되지 않는다. - Call by Reference:
변수의 주소를 전달하여 원본 값에 직접 접근한다.
아래 예시에서 modify()의 인자로 call by value(int)를 받았다면, main에서 modify(a)를 수행해도 a값이 바뀌지 않는다.
void modify(int& x) {
// 참조자로 전달
x = 20;
}
int main() {
int a = 10;
modify(a); // 원본 값 a가 변경됨
cout << a << endl; // 출력: 20
}
9. 포인터와 array
포인터는 변수의 메모리 주소를 저장하는 변수다.
- &a: 변수 a의 주소를 반환.
- *(&a): 주소 &a가 가리키는 값을 반환.
int a = 10; int* ptr = &a; // a의 주소를 ptr에 저장
cout << *ptr << endl; // 출력: 10
int* x와 int *x는 동일한 의미다.
또한 배열(array)는 첫 번째 요소의 주소를 가리키는 포인터로 동작한다.
2차원 배열은 행렬 형태로 데이터를 저장하지만, 내부적으로는 메모리의 연속된 주소를 사용한다.
array+1은 그 배열의 다음 값을 가리킨다.
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*ptr)[3] = arr; // 행(1D 배열)을 가리키는 포인터
cout << *(*ptr) << endl; // 출력: 1 (arr[0][0])
cout << *(*(ptr + 1) + 2) << endl; // 출력: 6 (arr[1][2])
10. 다형성 (Polymorphism)
다형성은 하나의 인터페이스로 여러 동작을 구현하는 개념이다.
- Function Overloading: 같은 이름의 함수가 여러 버전으로 정의된다.
- Operator Overloading: 연산자를 다양한 타입에 맞게 재정의할 수 있다.
- virtual 키워드를 사용하면, 객체의 실제 타입에 따라 적절한 함수가 호출된다.
- 런타임에 어떤 함수가 호출될지 결정되므로 동적 바인딩이라고 한다
class Shape {
public:
virtual void draw() {
cout << "Drawing Shape" << endl;
}
};
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing Circle" << endl;
}
};