- 암시적 캐스팅과 명시적 캐스팅
더보기
- 형변환(Casting)
해당 자료형을 다른 자료형으로 변환하는 것. - 암시적 형변환
컴파일러가 자료형을 변환해 주는 것을 의미합니다.
단, 형변환이 허용되는 경우이면서 프로그래머가 명시적으로 형변환을 안 할 경우에만 암시적 캐스팅이 일어납니다.
int Num1 = 3;
long Num2 = Num1;
// 암시적 캐스팅
// int 자료형에서 long 자료형으로 형변환이 허용됩니다.
// 프로그래머가 명시적으로 형변환하지 않았습니다.
// 따라서 암시적 형변환이 일어납니다. - C++의 명시적 형변환
프로그래머가 형변환을 위한 코드를 직접 작성한 것을 의미합니다.
C++에는 4가지 명시적 형변환들이 존재합니다
.이렇게 용도에 따라 나눈 이유는 프로그래머가 상황에 맞지 않는 C++ 캐스팅을 진행하려 할때,
컴파일러가 잘못된 캐스팅에 대한 에러를 발생시키게끔 하기 위함입니다.
- static_cast
- dynamic_cast
- reinterpret_cast
- const_cast
- static_cast
- C Style Casting Vs. C++ Style Casting
// C-Style Casting
int IntegerPI = (int)(3.141592f);
Dog* MyDog = new Dog();
Animal* Animal01 = (Animal*)(MyDog);
delete MyDog;
MyDog = nullptr;
const float ConstFloatPI = 3.141592f;
float FloatPI = (float)(ConstFloatPI);
// Primitive Type 간의 형변환에도 쓰이고, Class 간의 형변환에도 쓰이고, ...
// 만능간장소스인가..? 연두?..
// 내부적으로 어떤 일이 벌어질지는 우리도 알 수 없습니다.
// C++ Style Casting
int IntegerPI = static_cast<int>(3.141592f);
Dog* MyDog = new Dog();
Animal* Animal01 = dynamic_cast<Animal*>(MyDog);
delete MyDog;
MyDog = nullptr;
const float ConstFloatPI = 3.141592f;
const float* PtrToConstFloat = &ConstFloatPI;
float* PtrToFloat = const_cast<float*>(PtrToConstFloat);
// C++에서는 C와 다르게 캐스팅을 나누고 명확하게 적어줄 수 있습니다.
- static_cast<>()
더보기
- 업 캐스팅(Up-Casting) Vs. 다운 캐스팅(Down-Casting)
- 업 캐스팅(Up-Casting)
자식 클래스에서 부모 클래스로의 형변환을 업 캐스팅이라고 합니다.
- 다운 캐스팅(Down-Casting)
부모 클래스에서 자식클래스로의 형변환을 다운 캐스팅이라고 합니다. - static_cast<>()
컴파일 타임에 자료형을 검사하여 형변환합니다.
컴파일 과정에서 얻을 수 있는 자료형 정보(정적 자료형)를 토대로 형변환 가능한지 검사합니다.
검사 후 형변환 할 수 있다면 컴파일 성공, 형변환 할 수 없는 경우에는 컴파일도 실패합니다.
쉽게 말하자면, 변수의 자료형(무늬)으로만 판단합니다.
실제 객체의 자료형(동적할당시 호출되는 생성자, 힙메모리에 생성된 객체)은 검사하지 않습니다 - static_cast<>()를 정리하자면.
-초심자 기준
값 자료형(float, double, int, …) 간의 형변환 시에만 사용합시다.
포인터 자료형 간의 형변환 시에는 다음 단원에서 배우는 dynamic_cast만 사용합시다.
- 경험자 기준(기술면접 답변용)
정적 자료형 기준으로 형변환 가능한지를 검사합니다.
따라서 다운 캐스팅시에는 조심히 사용해야하는 경우가 있습니다.
다운 캐스팅시에는 dynamic_cast를 사용하는 것이 안전합니다.
- dynamic_cast<>()
더보기
- dynamic_cast<>()
런타임에 자료형을 검사하여 형변환합니다.
즉, 실제 객체의 자료형을 검사하여 형변환합니다.
만약 동적 자료형(런타임 자료형)을 검사했을 때 형변환 불가하다면 nullptr을 반환합니다. - RTTI(Run-Time Type Information, 런타임 타입 정보)
그러나 dynamic_cast를 쓰려면 RTTI를 켜야 합니다.
RTTI가 켜지면 각 객체마다 typeid를 얻어 올 수 있습니다.
이 typeid를 통해 어떤 클래스를 상속 받는지도 알 수 있습니다.
RTTI가 꺼지면 dynamic_cast는 업 캐스팅만 가능하고, 다운 캐스팅 시에는 컴파일 에러가 납니다 - 업 캐스팅과 다운 캐스팅에 대한 고찰
업 캐스팅, 즉 자식 클래스에서 부모 클래스로의 형변환은 사실 언제나 가능합니다.
ex) Cat 자료형은 무조건 Animal을 상속 받고 있으므로 가능. Cat is-a Animal은 언제나 참.
다운 캐스팅, 즉 부모 클래스에서 자식 클래스로의 형변환은 불분명합니다.
ex) Animal 클래스의 탈을 쓴 Dog 일수도, Cat 일수도, Bird 일수도… Animal is-a Cat은 참이 아닙니다.
그러니, static_cast나 dynamic_cast나 업 캐스팅에는 자신만만합니다. 무조건 성공입니다. - dynamic_cast를 정리하자면.
-초심자 기준
포인터 자료형 간의 형변환 시에는 dynamic_cast를 사용하자.
-경험자 기준(기술면접 답변용)
동적 자료형 기준으로 형변환 가능한지를 검사합니다.
실패시 nullptr을 반환하여, 업 캐스팅과 다운 캐스팅 모두 안전하게 사용 가능합니다.
또한 부모 클래스에 virtual 키워드가 단 한 개도 없다면,
부모-자식 클래스 간의 형변환은 컴파일 에러가 납니다.
- reinterpret_cast<>()와 const_cast<>()
더보기
- reinterpret_cast<>()
데이터의 비트 패턴을 수정하지 않고, 강제로 다른 자료형으로 형변환.
즉, 연관 없는 두 자료형 사이의 변환을 허용합니다. 심지어 포인터와 포인터 아닌 자료형 사이의 변환도 허용합니다.
C++ 명시적 캐스팅 중 가장 위험한 캐스팅입니다.
ex) Cat* <---> House*, char* <---> int*, Cat* <---> unsigned long long
Animal* MyPet = new Cat(2);
unsigned long long MyPetAddr = reinterpret_cast<unsigned long long>(MyPet);
// MyPet이 포인터이므로, 저장된 주소값을 화면에 출력하고자 unsigned long long형으로 형변환하고 싶습니다.
std::cout << "Address: " << std::hex << MyPetAddr << std::endl;
int* APInt = new int(-10);
// 비트패턴: 1111 1111 1111 1111 1111 1111 1111 0110
unsigned int* UAPInt = reinterpret_cast<unsigned int*>(APInt);
// 비트 패턴은 그대로 두고, unsigned int 자료형으로 해석합니다.
// 결과: 4294967286 - const_cast<>()
const 또는 volatile attribute를 제거할 때 사용합니다.
단, const_cast로 형변환은 불가능합니다.
Animal* MyPet = new Cat(2);
const Animal* PtrToMyPet = MyPet;
// ... 수십 줄 ...
// 대부분의 프로그래머들은 const를 없애기 위해 일부러 형변환을 하진 않을 것입니다.
// 수십 줄 뒤라 const를 못보고 실수로 바꾸려고 하는 사례가 더 많습니다.
Animal* MyAnimal = const_cast<Animal*>(PtrToMyPet);
// 컴파일 성공.
Cat* MyCat = const_cast<Cat*>(PtrToMyPet);
// 컴파일 에러. 형변환 할거면 다른 캐스트를 사용하라고 함.
- 인라인 함수
더보기
- 함수 호출 오버헤드
함수 호출의 비용은 무료가 아닙니다.
인자값을 어딘가에 저장해줘야하고, 해당 함수를 위한 스택 프레임을 할당해주기도 해야합니다.
물론 calling convention에 따라 달라질 수도 있긴 하나, 대부분 비슷한 비용이 들어갑니다. - 구현 자체가 매우 단순해서 함수 호출에 필요한 오버헤드를 떠안기에는 부담되는 경우가 있습니다.
이럴 때 해법이 바로 인라인 함수입니다.
int GetAge()
{
return Age;
} - 인라인 함수
함수 호출 대신 컴파일 타임에 코드가 복붙됩니다. 매크로 함수와 매우 유사합니다.
간단한 함수에 적합합니다. 특히 getter나 setter.
코드의 가독성과 성능 두마리 토끼를 잡은 문법입니다.
// Animal.h
class Animal
{
public:
Animal(int InAge);
inline int GetAge() const
{
return Age;
}
private:
int Age;
}; - 인라인 함수 주의사항
1. inline 키워드를 단다고 해서 무조건 해당 함수가 복붙되는게 아닙니다.
컴파일러에게 그렇게 해달라고 부탁하는 정도입니다.
2. 컴파일 타임에 복붙되게 하려면 인라인 함수는 헤더파일에 선언 및 정의가 필수적입니다.
컴파일 타임에는 각각의 .cpp 파일이 따로 컴파일 되기 때문에 서로의 존재를 모릅니다.
다만 헤더 파일은 인클루드 돼있기 때문에 헤더 파일에 inline 함수로 지정해두면 컴파일 타임에 복붙 될 수 있습니다.
3. 실행 파일의 크기가 증가하기 쉽니다.
동일한 코드를 여러 번 복붙하기 때문입니다. 남용하면 안됩니다. - 인라인 함수 Vs. 매크로 함수.
그냥 매크로 함수 쓰지 왜 인라인 함수를 따로 만들었을까요? 매크로 함수는 디버깅하기 힘들기 때문입니다.
call stack에 함수명도 보이지 않고, 중단점(break point)도 설정 불가능합니다.
매크로 함수는 범위(scope)도 준수하지 않습니다. 그냥 전역함수라서 이름 충돌도 나고 문제가 있습니다.
정말 정말 매크로를 쓸 이유가 있지 않는 한 인라인 함수를 씁시다.
인라인 함수는 컴파일 타임에 복붙되고, 매크로 함수는 전처리기 과정에서 복붙됩니다.
- extern 키워드와 static 키워드
더보기
- extern 키워드
해당 변수의 정의는 어딘가에 존재할 것이라고 컴파일러에게 선언하는 문법입니다.
즉, 변수를 생성하는 것이 아니고 존재한다고 약속만 하는 문법. 전방선언과 유사합니다.
전역 변수를 다른 파일에서도 접근할 수 있게 해줍니다. - static 키워드
변수를 어디에서나 접근할 수 있게끔 하는게 아니라 파일/클래스/함수 범위로 접근 제한하는 키워드. - 클래스 범위 static - 정적 멤버 변수
정적 멤버 변수도 스택 메모리가 아니라 데이터 섹션에 할당됩니다.
단, 정적 멤버 변수의 이름만 클래스에 소속됩니다.
따라서 객체 수에 따라 정적 멤버 변수의 개수가 증가하거나 감소하지 않습니다. 클래스 단위에 딱 1개 있습니다. - 함수 안에서 정적 변수를 쓰기보다는 클래스 안에 정의합시다.
OOP 기준으로 그냥 클래스 안에다가 넣어도 되니까, 클래스 안에 넣어둡시다.
함수 구현체 안찾아보고 헤더파일만 보고도 정적 변수를 볼 수 있기 때문입니다. - 전역 변수 대신 정적 멤버변수를 씁시다.
전역 변수를 쓰고 싶다면 public + 정적 멤버 변수 조합으로 대체합시다.
범위를 제한하기 위함입니다. - 클래스 범위 static - 정적 멤버 함수
클래스 범위에 제한된 전역 함수입니다. 객체가 없어도 정적 멤버 함수는 호출 할 수 있습니다.
멤버 함수와는 다르게 호출 시에 this 포인터를 필요로하지 않기 때문입니다. - static 키워드와 변수 접근
해당 변수를 특정할 수 있냐 없냐가 관건입니다.
멤버 함수의 멤버 변수 접근은 가능하다. 해당 객체(this)의 멤버 변수이므로 특정 가능. 멤버 함수의 정적 멤버 변수 접근은 가능하다. 정적 멤버 변수는 클래스 단위로 한 개만 존재하므로 특정 가능. 정적 멤버 함수의 멤버 변수 접근은 불가능하다. 어떤 객체의 멤버 변수인지 특정 불가. 정적 멤버 함수의 정적 멤버 변수 접근은 가능하다. 정적 멤버 변수는 클래스 단위로 한 개만 존재하므로 특정 가능.
'복습용 > C++' 카테고리의 다른 글
| [Unreal Engine 8기] C++ std::string과 File I/O (0) | 2026.03.25 |
|---|---|
| [Unreal Engine 8기] C++ 상속과 다형성, 추상 클래스 (1) | 2026.03.23 |
| [Unreal Engine 8기] C++ 복사 생성자와 오버로딩 (0) | 2026.03.20 |
| [Unreal Engine 8기] C++ 생성자와 소멸자 (0) | 2026.03.19 |
| [Unreal Engine 8기] C++ Console IO (0) | 2026.03.18 |