티스토리 뷰

반응형

모기를 잡으려면 모기약을 써야지 사람 잡는 약을 쓰면 되나

 

C스타일의 연산자는 어떤 것이든 다 변환한다.

사람이 실수를 해도 컴파일러는 이를 잡아낼 수가 없다. 

 

#include <iostream>


using namespace std;


class Car
{
private:
	int fuelGauge;
public:
	Car(int fuel):fuelGauge(fuel)
	{}
	void ShowCarState() { cout<<"잔여 연료량: " << fuelGauge << endl; }
};

class Truck :public Car
{
private:
	int freightWeight;
public:
	Truck(int fuel, int weight):Car(fuel),freightWeight(weight)
	{}
	void ShowTruckState()
	{
		ShowCarState();
		cout << "화물의 무게: " << freightWeight << endl;
	}
};

int main(void)
{
	Car* pcar1 = new Truck(80, 200);
	Truck* ptruck1 = (Truck*)pcar1;
	ptruck1->ShowTruckState();
	cout << endl;
	Car* pcar2 = new Car(120);
	Truck* ptruck2 = (Truck*)pcar2;
	ptruck2->ShowTruckState();
	return 0;
}

pcar1은 Truck 객체고, Truck형으로 참조하는 것은 자연스럽다.

pcar2는 Car 객체이기 때문에, Truck 형 변환은 자연스럽지 않다.

 

'기초 클래스의 포인터 형을 유도 클래스의 포인터 형으로 바꾸는 것은 일반적인 형 변환이 아니다.'

 

C++에서 이런 문제의 해결을 위해 4가지 형 변환 연산자를 제공한다.

-static_cast

-const_cast

-dynamic_cast

-reinterpret_cast

 

 

dynamic_cast:상속관계에서의 안전한 형 변환

 

dynamic_cast<T>(expr)

<>사이에 변환하고자 하는 자료형을 입력하고, 객체의 포인터 또는 참조형이 와야 하며, ()사이에는 변환의 대상이 와야한다.

 

안전한 형 변환이란?

'상속관계에 놓여 있는 두 클래스 사이에서 유도 클래스의 포인터 및 참조형 데이터를 기초 클래스의 포인터 및 참조형 데이터로 형 변환하는 경우'

 

#include <iostream>


using namespace std;


class Car
{
private:
	int fuelGauge;
public:
	Car(int fuel):fuelGauge(fuel)
	{}
	void ShowCarState() { cout<<"잔여 연료량: " << fuelGauge << endl; }
};

class Truck :public Car
{
private:
	int freightWeight;
public:
	Truck(int fuel, int weight):Car(fuel),freightWeight(weight)
	{}
	void ShowTruckState()
	{
		ShowCarState();
		cout << "화물의 무게: " << freightWeight << endl;
	}
};

int main(void)
{
	Car* pcar1 = new Truck(80, 200);
	Truck* ptruck1 = dynamic_cast<Truck*>(pcar1); //컴파일에러
	
	Car* pcar2 = new Car(120);
	Truck* ptruck2 = dynamic_cast<Truck*>(pcar2);//컴파일에러
	
	Car* pcar3 = new Truck(70,150);
	Car* ptruck3 = dynamic_cast<Car*>(ptruck3);//컴파일ok


	return 0;
}

 

Car->Truck(X)

Truck->Truck (X)

Truck->Car(O)

pcar2는 안되는 것 알겠는데, pcar1은 왜 안되나요?

-> 이에 static_cast를 사용

 

 

static_cast: A타입에서 B타입으로

 

static_cast<T><expr)

기초->유도(O)

유도->기초(O)

유도->유도(O) , 이런 경우는 별로 할 일이 없다.

 

모두 되기에, 조심해야한다.

 

 

static_cast:기본 자료형 간 변환

double->int 등에서 쓰인다.

 

그렇다면 원래 C 자료형과 차이는 무엇인가?

 

 

int main(void

{

 const int num=20;

 int*ptr=int* &num; //const 상수의 포인터는 const 포인터가 되어야 한다.

 *ptr=30; //상수 num이 실제로 변경된다..

 cout<<*ptr<<endl; //30출력

 float*adr=(float*)ptr; //int형 데이터를 float형으로 변환한다.

 cout<<*adr<<endl; //저장된 데이터를 float형으로 해석한다.

 

}

기본자료형 간 다른 포인터형 변환이 안된다.

static은 const 제거 불가.

 

 

const_caㄴt: const의 성향을 제거하라.

const_cast<T>(expr)

 

 

reinterpret_cast: 상관없는 자료형으로의 형 변환

reinterpret_cast<T>(exper)

 

클래스가 상속으로 관계를 맺은 것도 아닌 두 클래스에 사용할 수 있다.

 

int main(void)

{

 SimpleCar* car= new car;

 BestFriend* fren = reinterpret_cast<BestFriend*>(car)

}

 

#include <iostream>


using namespace std;


int main(void)
{
	int num = 0x010203;
	char* ptr = reinterpret_cast<char*>(&num);

	for (int i = 0; i < sizeof(num); i++)
		cout << static_cast<int>(*(ptr + i)) << endl;
	return 0;
}

출력결과

3

2

1

0

 

int형이 char형으로, char형이 int형으로 바뀌었다.

 

 

dynamic_cast 두 번째 이야기: Polymorphic 클래스 기반의 형 변환

-상속관계에 놓여있는 두 클래스 사이에서, 유도 클래스의 포인터 및 참조형 데이터를 기초 클래스의 포인터 및 참조형 데이터로 형 변환할 경우에는 dynamic_cast 연산자를 사용한다.

-반대로, 상속관계에 놓여있는 두 클래스 사이에서, 기초 클래스의 포인터 및 참조형 데이터를 유도 클래스의 포인터 및 참조형 데이터로 형 변환할 경우에는 static_cast 연산자를 사용한다.

 

기초클래스의 포인터 및 참조형 데이터를 유도 클래스의 포인터 및 참조형으로 형 변환을 허용한다.

'기초 클래스가 Polymorphic 클래스일 경우'

 

ploymorphic 클래스: 하나 이상의 가상함수를 지니는 클래스

 

#include <iostream>


using namespace std;


class SoSimple
{
public:
	virtual void ShowSImpleInfo()
	{
		cout << "SoSimple Base Class" << endl;
	}
};

class SoComplex :public SoSimple
{
public:
	void ShowSimpleInfo() // 이것 역시 가상함수
	{
		cout << "SoComplex Derived Class" << endl;
	}
};

int main(void)
{
	SoSimple* simPtr = new SoComplex;
	SoComplex* comPtr = dynamic_cast<SoComplex*>(simPtr);
	comPtr->ShowSImpleInfo();
	return 0;
}

결가

SoComplex Derived Class

 

유도클래스가 호출되었다. virtual이 없으면 에러가 발생한다.

 

 

정말 마지막까지 골치 아프게 하는군요.

그렇다면 dynamic_cast와 static_cast의 차이점은 무엇일까?

 

int main(void)

{

 SoSimple*SimPtr=new SoComplex;

 SoComplex*comptr= dynamic_cast<SoComplex*>(simptr);

}

기초->유도로 변경 성공

 

int main(void)

{

 SoSimple*SimPtr=new SoSimple;

 SoComplex*comptr= dynamic_cast<SoComplex*>(simptr);

}

유도가 기초가리키는 것 불가!

 

dynamic은 이처럼 위의 상항을 막아주지만, static은 그렇지 못하다.

 

 

프로그래머가 정의하지 않아도 발생하는 예외가 있다.

bad_cast 예외

 

#include <iostream>


using namespace std;


class SoSimple
{
public:
	virtual void ShowSImpleInfo()
	{
		cout << "SoSimple Base Class" << endl;
	}
};

class SoComplex :public SoSimple
{
public:
	void ShowSimpleInfo() // 이것 역시 가상함수
	{
		cout << "SoComplex Derived Class" << endl;
	}
};

int main(void)
{
	SoSimple simObj;
	SoSimple& ref = simObj;

	try
	{
		SoComplex& comRef = dynamic_cast<SoComplex&>(ref);
		comRef.ShowSImpleInfo();
	}
	catch (bad_cast expt)
	{
		cout << expt.what() << endl;
	}

	return 0;
}

결과

Bad dynamic_cast!

 

 

예외가 나타날 경우를 생각해 예외처리 문장을 설정해야한다.

 

 

 

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함
반응형