형변환 규칙

Jaemyeong Lee·2024년 11월 7일
0

FastCampusC++

목록 보기
74/78

코드를 한 줄씩 자세히 분석하여 설명드리겠습니다. 이 예제는 C++의 다양한 형변환 규칙과 형변환에 따른 동작 방식을 다루고 있습니다.

함수 오버로딩과 형변환 함수

void func(float f) { }
void func(Parent* parent) { }
void func(const Child& child) { }
  • func 함수는 서로 다른 파라미터 타입을 받는 오버로드된 세 가지 버전을 정의합니다.
    • func(float f): float 타입의 인자를 받습니다.
    • func(Parent* parent): Parent 포인터를 받습니다.
    • func(const Child& child): Child 클래스의 상수 참조를 받습니다.
  • 오버로딩된 func 함수들은 전달된 인자의 타입에 따라 호출됩니다.

형변환 연산자 정의

class Test
{
public:
    explicit operator bool() const
    {
        return true;
    }
};
  • Test 클래스에 bool 타입으로의 변환 연산자를 정의했습니다.
  • explicit 키워드를 사용하여 명시적 변환만 허용합니다. 즉, Test 객체를 bool로 변환할 때 자동 변환되지 않으며, 명시적으로 호출해야 합니다.

클래스 계층 구조

class Parent { };
class Child : public Parent { };
  • Parent 클래스와 이를 상속받는 Child 클래스를 정의했습니다.
  • ChildParent 클래스를 공개(public) 상속하며, 이를 통해 자식 클래스에서 부모 클래스 타입으로의 암시적 형변환이 가능합니다.

main 함수

int main()
{
    float f = 1;
    func(1);
  • float f = 1;에서 int1float로 암시적 형변환됩니다.
  • func(1);1float로 암시적 변환하여 func(float f) 버전을 호출합니다.

    char ch0 = 'a';
    int num0 = ch0;
  • char ch0 = 'a';는 문자 'a'를 저장합니다.
  • int num0 = ch0;charint로 암시적 형변환하며, 이는 promotion 또는 확대 변환이라고 불립니다.

    int num1 = 1000;
    char ch1 = num1;
  • char ch1 = num1;intchar로 암시적 변환하는 demotion(축소 변환)입니다. char의 크기보다 큰 값을 저장하려는 경우 데이터 손실이 발생할 수 있습니다.

Uniform Initialization (통합 초기화)

    const int num2 = 10;
    char ch2{ num2 };
  • char ch2{ num2 };에서 {}를 사용한 통합 초기화는 축소 변환이 필요한 경우 컴파일 타임에 오류를 발생시킵니다.
  • 상수 num2char에 맞는 값이므로 정상적으로 초기화됩니다.

형변환과 오버플로우, 언더플로우

    unsigned short s0 = 40000;
    cout << s0 + s0 << endl;
    cout << typeid(s0 + s0).name() << endl;
  • s0 + s0에서 unsigned short 값이 intpromotion되어 계산됩니다. typeid를 통해 결과 타입을 확인할 수 있습니다.
    unsigned int i0 = 4100000000;
    cout << i0 + i0 << endl;
    cout << typeid(i0 + i0).name() << endl;
  • i0 + i0에서 오버플로우가 발생합니다. unsigned int 타입으로 남으며, 결과 값이 unsigned int 범위를 초과해 오버플로우됩니다.
    unsigned int i1 = 10;
    int i2 = -110;
    cout << i0 + i2 << endl;
    cout << typeid(i0 + i1).name() << endl;
  • i0 + i2에서 unsigned가 포함된 연산은 결과가 항상 unsigned가 됩니다. 따라서 int 값이 unsigned int로 암시적 변환되어 언더플로우가 발생할 수 있습니다.
    long long l0 = 10;
    cout << l0 + i1 << endl;
    cout << typeid(l0 + i1).name() << endl;
  • l0 + i1에서 i1long long 타입으로 암시적 변환되어 결과가 long long이 됩니다.

실수와 정수 간의 연산

    float f = 1.f;
    unsigned long long ull = 10ULL;
    cout << typeid(f + ull).name() << endl;
  • f + ull에서 unsigned long longfloat 타입으로 변환되어 실수 연산이 수행됩니다.
  • 실수 연산 결과는 큰 타입으로 변환됩니다(long double > double > float).

Test 객체의 암시적 변환

    Test t;
    bool b = t;
    if (t) {}
    while (t) {}
    t ? 1 : 2;
    !t;
    t && true;
    false || t;
  • Test 객체 tbool로 암시적 변환하려 할 때 explicit 키워드로 인해 bool b = t;는 컴파일되지 않습니다.
  • 그러나 if, while, 삼항 연산자, 논리 연산자 등에서는 암시적 변환이 허용됩니다.

const 형변환

    int a = 1;
    const int& b = a;
    const int* c = &a;
  • int aconst int& 또는 const int*로 암시적 형변환됩니다. 이는 상수화(const-casting)라고 하며, 원본 값 a의 수정은 허용되지 않습니다.

부모-자식 간의 형변환

    Child c;
    Parent* p0 = &c;
    Parent& p1 = c;
    func(&c);
    func(c);
  • Child 타입의 객체 cParent* 또는 Parent& 타입으로 암시적 변환할 수 있습니다. 이를 통해 부모 타입으로 형변환이 이루어집니다.

명시적 형변환

    (Child*)c;
    (Child*)(c);
}
  • 이 부분은 Child 객체로의 명시적 형변환을 보여줍니다.
profile
李家네_공부방

0개의 댓글