1. explicit 키워드와 암시적 형변환 제어
(1) 변환 생성자 (Conversion Constructor)
매개변수가 하나인 생성자는 컴파일러에 의해 암시적 형변환(Implicit Conversion)에 사용될 수 있다. 이를 변환 생성자라 한다.
- 문제점: 개발자가 의도하지 않은 시점에 임시 객체가 생성되어 로직 버그 및 성능 저하를 유발할 수 있다.
(2) explicit의 역할
생성자 앞에 explicit을 선언하면 컴파일러의 자의적인 형변환을 금지하고, 반드시 명시적 호출 시에만 객체가 생성되도록 강제한다.
| 구분 | 직접 초기화 (T a(b);) | 복사 초기화 (T a = b;) |
| 일반 생성자 | 허용 | 허용 |
| explicit 생성자 | 허용 | 차단 (컴파일 에러) |
class Gold {
public:
int Amount;
explicit Gold(int InAmount) : Amount(InAmount) {}
};
void Upgrade(Gold InGold) {}
int main() {
// Upgrade(1000); // 에러: int에서 Gold로 암시적 변환 불가
Upgrade(Gold(1000)); // OK: 명시적 생성
Gold MyGold(500); // OK: 직접 초기화
// Gold MyGold2 = 500; // 에러: 복사 초기화 차단
}
2. 형변환 연산자 (Type Conversion Operator)
(1) 정의
객체를 기본 자료형이나 다른 클래스 타입으로 변환할 때 사용한다. 변환 생성자와는 정반대의 방향(객체 → 타입)으로 동작한다.
(2) explicit operator
C++11부터 형변환 연산자에도 explicit을 붙일 수 있다. 이는 if문과 같은 논리 판단 위치를 제외하고는 static_cast를 통한 명시적 변환만을 허용한다.
C++
class GameClient {
public:
bool bIsConnected = true;
explicit operator bool() const { return bIsConnected; }
};
GameClient Client;
if (Client) { /* OK: 논리 판단에서는 허용 */ }
// bool bCheck = Client; // 에러: 암시적 변환 불가
bool bCheck = static_cast<bool>(Client); // OK: 명시적 변환
3. C++ 4대 형변환 (Casting)
C 스타일 캐스트((int)var)는 컴파일 타임 체크가 부족하여 위험하므로, 용도에 맞는 C++ 전용 캐스트 사용을 권장한다.
| 종류 | 용도 | 특징 |
| static_cast | 일반적 형변환 | 컴파일 타임에 논리적 적합성 검사. 가장 많이 사용됨. |
| dynamic_cast | 안전한 다운캐스팅 | 런타임에 상속 계층 구조 확인. 실패 시 nullptr 반환. |
| const_cast | 상수성 제거 | 포인터나 참조자의 const 속성만 제거. |
| reinterpret_cast | 강제 비트 재해석 | 서로 관련 없는 타입(포인터 $\leftrightarrow$ 정수 등) 간 강제 변환. |
4. mutable 키워드와 논리적 상수성
(1) 정의
const 멤버 함수 내부에서도 값을 수정할 수 있게 허용하는 키워드이다.
(2) 사용 목적 (Logical Constness)
외부에서 보기에 객체의 상태는 변하지 않지만(상수 함수), 내부적으로 통계(접근 횟수)나 캐싱을 위해 변수를 수정해야 할 때 사용한다. const_cast보다 설계 의도가 명확하므로 안전하다.
class Monster {
private:
int HP = 100;
mutable int AccessCount = 0;
public:
int GetHP() const {
AccessCount++; // const 함수 내에서도 수정 가능
return HP;
}
};
5. 메모리 영역 구조 (Memory Layout)
프로그램이 실행될 때 메모리는 권한과 목적에 따라 세분화된다.
(1) 영역별 분류
| 영역 | 저장 내용 | 권한 | 수정 가능 여부 |
| Code | 기계어 명령문 | Read-Only | 불가 |
| Data (RO) | const 전역 변수, 리터럴 | Read-Only | 불가 |
| Data (RW) | 초기화된 전역/정적 변수 | Read-Write | 가능 |
| BSS | 초기화되지 않은 전역/정적 변수 | Read-Write | 가능 (0으로 초기화됨) |
| Stack | 지역 변수, 매개변수 | Read-Write | 가능 (자동 관리) |
| Heap | 동적 할당 (new) | Read-Write | 가능 (사용자 관리) |
(2) Data vs BSS 관점
- Data: 초기값이 있는 변수를 저장하며, 실행 파일 내에 공간을 차지한다.
- BSS: 초기값이 없는 변수를 저장하며, 실행 파일의 크기를 늘리지 않고 실행 시점에 공간만 할당받는다.
(3) 상수성 위반 주의
constexpr 객체나 문자열 리터럴은 Data(RO) 영역에 위치한다. 이를 const_cast로 강제 수정하려 할 경우, OS 수준에서 Access Violation(런타임 크래시)을 발생시켜 무결성을 보호한다.
6. 종합 요약
- Safety: 단일 인자 생성자에는 explicit을 기본으로 사용하여 휴먼 에러를 방지한다.
- Clarity: static_cast를 통해 명시적으로 타입을 확정하여 코드 가독성을 높인다.
- Design: mutable을 통해 논리적 상수성을 유지하고, 메모리 영역의 특성을 고려하여 불필요한 힙 할당을 지양한다.
'C++ 공부' 카테고리의 다른 글
| [C++ Study] 가상 함수와 V-Table: 동적 바인딩의 내부 메커니즘 (0) | 2026.04.19 |
|---|---|
| [C++ Study] 객체지향 설계의 핵심: 관계 정의와 다형성 (Is-A, Has-A, Casting) (0) | 2026.04.18 |
| [C++ Study] friend, 상속의 경계, 그리고 static의 메모리 전략 (0) | 2026.04.10 |
| [C++ Study] Side Effect, Android Vulkan, 그리고 현대적 상수(const/constexpr/consteval) (0) | 2026.04.09 |
| [C++ Study] 열거형, 복사 생성자, 그리고 메모리 관리 전략 (0) | 2026.04.08 |