타입 변환 2

 

인프런 Rookiss님의 'Part1: C++ 프로그래밍 입문' 강의를 기반으로 정리한 필기입니다. 
😎[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 강의 들으러 가기!

 

 


 

공통 부분  -  Knight, Dog, BullDog 

 

class Knight
{
public:
    int _hp = 10;
};

class Dog
{
public:
    Dog() {    }

    // 타입 변환 생성자
    Dog(const Knight& knight)
    {
        _age = knight._hp;
    }

    // 타입 변환 연산자
    operator Knight()
    {
        return (Knight)(*this);
    }

public:
    int _age = 1;
    int _cuteness = 2;
};

class BullDog : public Dog
{
public:
    bool _french;   // 프렌치 불독
};

 


 

아무런 연관 관계가 없는 클래스 사이의 변환

 

 


 

 

1. 연관없는 클래스 사이의 '값 타입' 변환

 

-  연관없는 클래스 사이의 '값 타입' 변환은 일반적으로 안 됨

예외: 타입 변환 생성자, 타입 변환 연산자

 

	Knight knight;
    Dog dog = (Dog)knight;

    Knight knight2 = dog;

 


 

 

2. 연관없는 클래스 사이의 참조 타입 변환

 

	Knight knight;
	// 어셈블리 관점에서는 '포인터 = 참조'

	// [ 주소 ] -> [ Dog ]
    Dog& dog = knight; 		// 다음과 같이 암시적으로 선언하면 통과X
	Dog& dog = (Dog&)knight;// (Dog&)와 같이 명시적으로 선언하면 통과O
	dog._cuteness = 12;		// 건드리면 안되는 메모리를 건드리는 문제발생!

 


 

 

상속 관계에 있는 클래스 사이의 변환

 

 


 

 

 

[1] 상속 관계 클래스의 값 타입 변환

 

	// Dog dog;
	// BullDog bulldog = (BullDog)dog;

	BullDog bulldog;
	Dog dog = bulldog;

위의 경우 통과X, 아래의 경우 통과O

특징)  부모->자식 NO  /  자식->부모 OK 


 

 

 

[2] 상속 관계 클래스의 참조 타입 변환

 

	Dog dog;
    BullDog& bulldog = dog;				// 통과X
	BullDog& bulldog = (BullDog&)dog;	// 통과O

	// [age, cuteness, french ]
	BullDog bulldog;
	Dog& dog = bulldog;

 

 


 

 

 

 

결론

 

[값 타입 변환] 

진짜 비트열도 바꾸고~ 논리적으로 말이 되게 바꾸는 변환

-  논리적으로 말이 된다? (ex. BullDog -> Dog) OK

-  논리적으로 말이 안 된다 (ex. Dog -> BullDog, Dog -> Knight) 안 됨

 

 

[참조 타입 변환] 

비트열은 냅두고 우리의 '관점'만 바꾸는 변환

- 땡깡 부리면(명시적 요구) 해주긴 하는데, 말 안 해도 '그냥' (암시적)으로 해주는지는 안전성 여부를 연관 있음

  • 안전하다? (ex. BullDog -> Dog&)
    • '그냥' (암시적으로) OK
  • 위험하다? (ex. Dog -> BullDog&)  
    • 메모리 침범 위험이 있는 경우는 '그냥' (암시적으로) 해주진 않음 (위험하니까)  
    • 명시적으로 정말 정말 하겠다고 최종 서명을 하면 OK

 

 

전체코드

더보기
#include <iostream>
using namespace std;

class Knight
{
public:
    int _hp = 10;
};

class Dog
{
public:
    Dog() {    }

    // 타입 변환 생성자
    Dog(const Knight& knight)
    {
        _age = knight._hp;
    }

    // 타입 변환 연산자
    operator Knight()
    {
        return (Knight)(*this);
    }

public:
    int _age = 1;
    int _cuteness = 2;
};

class BullDog : public Dog
{
public:
    bool _french;   // 프렌치 불독
};


int main()
{
    // -------- 아무런 연관 관계가 없는 클래스 사이의 변환 ---------- 

    // [1] 연관없는 클래스 사이의 '값 타입' 변환
    // 특징) 일반적으로 안 됨 (예외: 타입 변환 생성자, 타입 변환 연산자)

    {
        Knight knight;
        Dog dog = (Dog)knight;

        Knight knight2 = dog;
    }

    // [2] 연관없는 클래스 사이의 참조 타입 변환
    // 특징) 명시적으로는 OK
    {
        Knight knight;
        // 어셈블리 : 포인터 = 참조

        // [ 주소 ] -> [ Dog ]
        Dog& dog = (Dog&)knight;
        dog._cuteness = 12;
    }

    // -------- 상속 관계에 있는 클래스 사이의 변환 ---------- 
    // 특징) 자식->부모 OK   /  부모->자식 NO
    // [1] 상속 관계 클래스의 값 타입 변환

    {
        // Dog dog;
        // BullDog bulldog = (BullDog)dog;

        BullDog bulldog;
        Dog dog = bulldog;
    }

    // [2] 상속 관계 클래스의 참조 타입 변환
    // 특징) 자식->부모 OK   /  부모->자식 (암시적 NO) (명시적 OK)
    {
        Dog dog;
        BullDog& bulldog = (BullDog&)dog;

        // [age, cuteness, french ]
        BullDog bulldog;
        Dog& dog = bulldog;
    }

    // 결론)
    // [값 타입 변환] : 진짜 비트열도 바꾸고~ 논리적으로 말이 되게 바꾸는 변환
    // - 논리적으로 말이 된다? (ex. BullDog -> Dog) OK
    // - 논리적으로 말이 안 된다 (ex. Dog -> BullDog, Dog -> Knight) 안 됨
    // [참조 타입 변환] : 비트열은 냅두고 우리의 '관점'만 바꾸는 변환
    // - 땡깡 부리면(명시적 요규) 해주긴 하는데, 말 안 해도 '그냥' (암시적)으로 해주는지는 안전성 여부를 연관 있음
    // -- 안전하다? (ex. BullDog -> Dog&) '그냥' (암시적으로) OK
    // -- 위험하다? (ex. Dog -> BullDog&)
    // --- 메모리 침범 위험이 있는 경우는 '그냥' (암시적으로) 해주진 않음 (위험하니까)
    // --- 명시적으로 정말 정말 하겠다고 최종 서명을 하면 OK

    return 0;
}