C++

[C/C++ 강좌] 83강. 상속에서의 형변환 (2) - 다운캐스팅

코다람쥐 2022. 1. 20. 14:30

https://www.youtube.com/watch?v=ZGji0PxM1Y4&list=PLlJhQXcLQBJqywc5dweQ75GBRubzPxhAk&index=88

 

1. static_cast (정적형변환)

프로그래머의 실수로 상속관계의 클래스가 아닌 서로 전혀 관계없는 클래스끼리 형변환을 할 수도 있다.

#include <iostream>
using namespace std;

class Base {
public:
	int a = 1;
};

class Drv1 : public Base {
public:
	void f() {
		cout << "Drv1::f()" << endl;
		cout << b << endl;
	}
	float b = 3.14;
};

int main() {
	Base* b = new Drv1;
	int* a = new int(5);
	Drv1* d1 = (Drv1*)a; // 서로 관련없는 자료형끼리 캐스팅으로 프로그래머의 실수
	d1->f();

	delete b;
}

위와 같은 코드는 실제로 구문오류는 뜨지않는다.

어처구니 없는 실수지만 코드가 길어지면 프로그래머가 이런 실수를 저지르지 말란 법은 없다.

이러한 실수를 막아주기위해 static_cast키워드를 사용하면된다.

	Drv1* d1 = static_cast<Drv1*>(a);

이렇게 static_cast를 선언해주면 int형과 Drv1형은 서로 아무런 관련이 없기 때문에 구문오류가 발생한다.

	Drv1* d1 = static_cast<Drv1*>(b); // 다운캐스팅이므로 허용!

그리고 위의 코드는 컴파일러에서 다운캐스팅이라고 생각하여 구문오류가 발생하지 않는다.

 

 

하지만 정적캐스트도 근본적으로 문제가 있다. 그것은 C++에서 막아놓은게 아닌 프로그래머가 조심해서 사용해야 한다는 것이다.

#include <iostream>
using namespace std;

class Base {
public:
	int a = 1;
};

class Drv1 : public Base {
public:
	void f() {
		cout << "Drv1::f()" << endl;
		cout << b << endl;
	}
	float b = 3.14;
};

class Drv2 : public Base {
public:
	void f() {
		cout << "Drv2::f()" << endl;
		cout << c << endl;
	}
	int c = 3;
};

int main() {
	Base* b = new Drv1;
	int* a = new int(5);
	Drv2* d2 = static_cast<Drv2*>(b); // 서로 관련없는 자료형끼리 캐스팅
	d2->f();

	delete b;
}

새로운 Drv2클래스를 추가하였다.

만약 Base *b 포인터는 Drv1을 가리키고 있는데 b를 Drv2로 정적 캐스팅을 한다고하면 메모리 상에 이상하게 덮어 씌워져서 제대로 된 값을 얻기 힘들다.

이러한 점을 주의해서 써야한다는 것이 근본적인 문제점이며 이러한 문제점을 해결할 수 있는게 동적 캐스팅이다.