Implicit Conversion(묵시적 형변환)
묵시적 형변환과 명시적 형변환
묵시적(암시적) 형변환: implicit conversion
- 형변환을 겉으로 드러내지 않음
명시적 형변환: explicit conversion
- 형변환을 명시한다
변환 생성자
#include <iostream>
#include <string>
using namespace std;
class Item {
public:
Item(int num) : num(num) { // 변환 생성자
cout << "Item(int)" << '\n';
}
Item(string name) : name(name) { // 변환 생성자
cout << "Item(string)" << '\n';
}
Item(int num, string name) : num(num), name(name) {
cout << "Item(int, string)" << '\n';
}
void print() {
cout << num << " : " << name << endl;
}
private:
int num;
string name;
};
int main(void) {
Item i1 = Item(1);
Item i2(2);
Item i3 = 3; // 변환 생성자(int num)
i3 = 3;
// 3을 item객체로 변환시킴(임시객체 생성) --> 이동생성자를 통해 i3로 대입
// 묵시적 변환
Item i4 = (Item)4; // Item(int num) 생성자가 형 변환까지 하고 있음.
// 명시적 변환
전부 Item(int num) 생성자를 호출
- 우리가 알고 있는 일반적인 일반적인 생성자의 역할도 하지만, 변환 생성자의 역할도 한다.
Item i3 = 3;
- 변환 생성자에서 임시 객체를 생성한 후 임시 객체를 통해서 i3를 초기화
i3 = 3
컴파일러는 정수 3이 i3로 변환될 수 있는지를 찾는다.
변환 생성자가 존재 -> 변환 생성자 Item(int)가 호출되어 임시 객체가 생성된다
기본 대입 연산자를 통해 i3에 대입된다
아래 코드도 변환 생성자를 통해 대입된다
Item i5(5);
i5 = string("stone");
- 그러면 파라미터가 2개인 생성자를 호출하면?
Item i6(1, "grass");
Item i7 = { 2, "dirt" };
// 다음도 가능
i7 = { 2, "dirt" }; // C++11 문법, 묵시적 변환
Item i8{ 3, "wood" };
매개변수가 2개인 경우에 대해서도 위에서 본 것과 같이 변환 생성자를 통해서 작동한다
실제로 테스트를 해보자
i1.print();
i2.print();
i3.print();
i4.print();
i5.print();
i6.print();
i7.print();
i8.print();
형변환 연산자 오버로딩
- 다음은 불가능하다
int itemNum = (int)i8;
- 형변환도 연산자이기 때문에, 연산자 오버로딩을 해줄 수 있다.
class Item {
// Item -> int 형변환 연산자 오버로딩
operator int() const { // explicit operator int() : 명시적으로만 가능하게
return num;
}
}
반환 타입을 operator 키워드 뒤에 적어줌
연산자에서 반환 타입을 알 수 있기 때문에 operator 앞에 int 등의 타입을 안 적는 것
객체 자체가 안바뀌도록 const를 붙여주는게 일반적이다
이렇게 하면 위에서 불가능 했던 것이 가능해짐
int itemNum1 = (int)i8;
// 묵시적도 가능하다
int itemNum2 = i7;
- String 타입으로도 바꿔보자
// Item -> string
operator string() const {
return to_string(num) + " : " + name;
// 참고) to_string : 숫자를 문자열로 반환하여 return
}
void println(string s) {
cout << s << endl;
}
- 출력을 해보자
int itemNum = (int)i8; // 명시적
int itemNum2 = i7; // 묵시적
cout << itemNum << endl;
cout << itemNum2 << endl;
println((string)i8); // 명시적 형변환
println((int)i8);
- 만약 다음과 같이 출력한다면?
println(i8);
string으로 묵시적 형변환이 일어난다
만약 다음과 같은 함수가 추가로 존재한다면?
void println(int n) {
cout << n << endl;
}
println(i8)에서 오류가 발생한다.
- 묵시적 형변환시 i8을 string으로? Int로? 어떤 걸로 변환해야 하는지 모호성 발생
explicit 키워드
형변환 연산자 앞에 explicit 키워드를 붙여주면 묵시적으로 해당 형변환 연산자가 실행되지 않도록 만든다
주로 원하지 않은 다른 타입으로 묵시적 변환이 발생하는 것을 방지하기 위해 사용한다
explicit operator string() const {
return to_string(num) + " : " + name;
}
- 변환 생성자에 explicit을 붙여주면 묵시적으로 Item형 임시 객체를 만드는 것이 불가능해져서 에러가 발생한다
class Item {
public:
explicit Item(int num) : num(num) { // 변환 생성자 // explicit Item(int num) : 명시적으로만 가능하게
cout << "Item(int)" << '\n';
}
explicit Item(string name) : name(name) { // 변환 생성자
cout << "Item(string)" << '\n';
}
explicit Item(int num, string name) : num(num), name(name) {
cout << "Item(int, string)" << '\n';
}
/* 이하 생략 */
}
int main(void) {
Item i1 = Item(1);
Item i2(2);
Item i3 = 3; // 에러 발생 : 묵시적 형변환 불가
i3 = 3; // 에러 발생 : 묵시적 형변환 불가
'Programming Language > C++' 카테고리의 다른 글
[C++] 상속이 필요한 이유(1) (0) | 2024.06.27 |
---|---|
[C++] 상속(Inheritance)과 접근제어(Access Control) (0) | 2024.06.27 |
[C++] 이동 시맨틱(Move Semantics): 이동 생성자, 이동 대입 연산자 (0) | 2024.06.27 |
[C++] 대입 연산자 오버로딩 (0) | 2024.03.12 |
[C++] 복사 생성자 오버로딩 (0) | 2024.03.12 |