[C++] 타입 변환 연산자 오버로딩

Seongcheol Jeon·2025년 7월 9일
0

CPP

목록 보기
46/47
post-thumbnail

타입 변환 연산자 오버로딩

사용자가 직접 정의해서 사용할 수 있는 타입 변환은 두 가지가 있다.

  1. 생성자를 이용한 타입 변환.
  2. 타입 변환 연산자 오버로딩을 이용한 타입 변환.

생성자를 이용한 타입 변환

특정 타입을 인자로 받는 생성자가 있다면 생성자 호출을 통한 타입 변환(객체 생성 후 대입)이 가능하다. 생성자를 이용해 다른 타입을 자신의 타입으로 변환할 수 있다.

#include <iostream>

using namespace std;


class A
{

};

class B
{
public:
    B() { cout << "B() 생성자" << endl; }
    B(A& _a) { cout << "B(A& _a) 생성자" << endl; }
    B(int n) { cout << "B(int n) 생성자" << endl; }
    B(double d) { cout << "B(double d) 생성자" << endl; }
};

int main()
{
    A a;
    int n = 10;
    double d = 5.5;

    B b; // B() 생성자 호출
    b = a; // b = B(a) 암시적 생성자 호출 후 대입
    b = n; // b = B(n) 암시적 생성자 호출 후 대입
    b = d; // b = B(d) 암시적 생성자 호출 후 대입

    return 0;
}

/* 결과
B() 생성자
B(A& _a) 생성자
B(int n) 생성자
B(double d) 생성자
*/

b = a에서 컴파일러A 타입의 객체를 B 타입으로 변환하기 위해 생성자를 확인한다. A 타입의 객체(a)를 인자로 받는 생성자가 있으므로 이 생성자를 호출해 B 타입의 객체를 생성한다.

아래의 Point 객체에 정수를 대입한다면 컴파일이 가능할까? 정답은 가능하다이다. 그 이유는 정수를 인자로 받는 생성자가 있기 때문이다.

#include <iostream>

using namespace std;

class Point
{
public:
    Point(int x = 0, int y = 0) : x(x), y(y) {}
    void Print() const{ cout << x << ", " << y << endl; }

private:
    int x;
    int y;
};

int main()
{
    Point pt;
    pt.Print();

    pt = 10; // Point(10, 0) 암시적 생성자 호출
    pt.Print();

    return 0;
}

pt = 10에서 정수를 인자로 받는 생성자가 있으므로 컴파일러Point(10, 0)을 호출해 Point 객체생성한다. 이렇게 하면 실수로 Point 객체에 정수를 대입해도 컴파일이 성공하여 버그로 연결된다.😱
그래서 생성자를 이용한 형변환을 의도하지 않는다면, 생성자는 명시적 호출만 가능하도록 explicit 키워드를 지정한다.

다음은 Point 생성자에 explicit 키워드를 지정한 예이다.

#include <iostream>

using namespace std;

class Point
{
public:
    explicit Point(int x = 0, int y = 0) : x(x), y(y) {}
    void Print() const{ cout << x << ", " << y << endl; }

private:
    int x;
    int y;
};

int main()
{
    Point pt;
    pt.Print();

    // pt = 10; // 에러! 암시적 생성자 호출 불가능.
    pt = Point(10); // 명시적 생성자 호출만 가능!
    pt.Print();

    return 0;
}

explicit 생성자명시적호출만 가능하므로 Point(10)과 같이 호출한다.

📌 암시적인 생성자 형 변환을 의도하지 않는 한, 인자를 갖는 생성자는 모두 explicit 생성자로 만들자!

타입 변환 연산자 오버로딩을 이용한 타입 변환

타입 변환 연산자 오버로딩을 사용하면 자신의 타입을 다른 타입으로 변환할 수 있다.

#include <iostream>

using namespace std;

class A
{

};

class B
{
public:
    operator A()
    {
        cout << "operator A() called" << endl;
        return A();
    }

    operator int()
    {
        cout << "operator int() called" << endl;
        return 55;
    }

    operator double()
    {
        cout << "operator double() called" << endl;
        return 3.14;
    }
};

int main()
{
    A a;
    int n;
    double d;

    B b;
    a = b; // b.operator A() 암시적 호출
    n = b; // b.operator int() 암시적 호출
    d = b; // b.operator double() 암시적 호출

    cout << endl;
    a = b.operator A(); // 명시적 호출
    n = b.operator int(); // 명시적 호출
    d = b.operator double(); // 명시적 호출

    return 0;
}

/* 결과
operator A() called
operator int() called
operator double() called

operator A() called
operator int() called
operator double() called
*/

a = b에서 컴파일러B타입 객체(b)A 타입으로 변환하기 위해 타입 변환 연산자 b.operator A() 멤버 함수를 호출한다.

❗주의할 점은 타입 변환 연산자생성자소멸자처럼 반환 타입을 지정하지 않는다.

다음의 예제는 Point 클래스 타입을 정수 타입으로 변환할 수 있게 타입 변환 연산자오버로딩한다.

#include <iostream>

using namespace std;

class Point
{
public:
    explicit Point(int x = 0, int y = 0) : x(x), y(y) {}
    void Print() const { cout << x << ", " << y << endl; }
    operator int() const
    {
        return x;
    }

private:
    int x;
    int y;
};

int main()
{
    int n = 10;

    Point pt(2, 3);
    n = pt; // pt.operator int() 암시적 호출
    cout << n << endl;

    return 0;
}

/* 결과
2
*/

n = ptpt.operator int() const 멤버 함수를 호출해 ptx 값을 반환한다. const 객체비 const 객체 모두 타입 변환이 가능하게 const 멤버 함수로 정의한다.

0개의 댓글