수업기록 #다형성
부모 소멸자만 호출되고 자식 소멸자가 호출되지 않는 이유! 객체를 할당할 때에는 new 자식 자료형 으로 호출하기 때문에 new 연산자는 자식 자료형의 생성자와 부모 생성자를 호출하지만 delete할 때에는 delete연산자는 부모 자료형을 해제하기 때문에 자식 소멸자가 불리지 않는다.
그래서 부모 소멸자에는 오버라이드해주어야 한다. (소멸자의 경우에는 ~()가 실제 함수 호출하는 것이고, 그 사이에 붙은 함수 이름은 사실 어떤 자료형인지를 명시해주는 것일 뿐. 그래서 부모와 자식의 함수 형식이 같다고 봐도 된다.)
class CBase{
public :
virtual void Render() =0; //순수 가상함수 : 오버라이딩을 하기 위한 도구
}
부모의 기능이 아예 필요가 없을 때, 부모 함수의 선언에 = 0을 붙여주면 됨. 가상 함수가 ‘하나’라도 생기게 되면 그 클래스는 추상클래스 가 되기 때문에 객체를 생성할 수 없게 된다.
추상클래스에게 상속받는 모든 자식은 ‘필수로’ 해당 가상 함수의 몸체를 구현해주어야 한다. (추상 함수는 가상함수 테이블 생성의 요건이 되지 않는다 : 객체 생성이 안되니까)
class CTemp abstract{ }
→ 추상클래스라고 명시적으로 알려주는 키워드
`class CTemp final : clas Parent{ } → 최말단의 클래스(마지막 상속자)라고 명시적으로 알려주는 것
오버라이딩을 사용하기에는 다른 자식들과 공통화하기에는 애매한 상황에서 사용하는 문법.
강제 형변환 : 다형성의 강제 캐스팅이라고 보긴 어려움
CObj->CPlayer //상속 관계
CObj* pPlayer= new CPlayer;
(CPlayer*) pPlayer;
부모 포인터지만, 플레이어 포인터로 형변환 하는 것 : 일시적인 형변환일 뿐 이는 강제적으로 다른 클래스의 함수를 부를 수 있기에 위험함
즉, CMonster 클래스로 강제 형변환하게 되면 객체를 CPlayer타입으로 객체를 생성했어도 CMonster의 함수를 부를 수 있게 됨. (컴파일러 상에서는 문제가 없으니까.)
C++ 캐스팅 ‘연산자’ #캐스팅
static_cast
정적 캐스팅 : 컴파일 시점에 캐스팅을 수행 :: 동작 속도가 빠르다.
논리적인 형변환을 해주며 C스타일의 캐스트와 사실상 같다. (float)i
그렇지만 C언어 캐스트보다는 안전함(비논리적인 캐스팅을 막아줌)
static_cast<int>(iNumber) 다만, 상속관계일 때에는 논리적인 과정으로 비논리적인 결과를 보여줄 수 있음 즉 런타임시 작동하는 보안/문법적 오류 검사가 안됨
다운캐스팅
dynamic_cast 다형성
동적 캐스팅 : 런타임 시점에 캐스팅을 수행 :: 동작 속도가 느리다.
다운 캐스팅을 위한 목적으로 설계되었기에
- 클래스가 상속 관계이며
- 부모 클래스에 가상함수가 1개라도 있어야 함. (동적으로 움직이기 위해서는 가상함수가 필요하기 때문에)
- 일반적인 자료형은 캐스팅할 수 없다.
dynamic_cast<CPlayer>런타임에 작동하기 때문에 런타임 시에 비논리적인 형변환이 발견이 되면 널포인터를 반환하게 된다. (주의, 널포인터 반환해도 함수 호출은 가능 : 캐스팅은 수행한다는 뜻) → 널포인터는 반환은 하는데 캐스팅 수행은 해 #RTTI → Runtim Type Information → 가상함수가 있는 상속관계가 있어야 함 내가 사용하고 있는 자료형이 누굴 참조하는 문법>? 확인완료 RTTI
const_cast
포인터나 레퍼런스의 const 성격을 벗겨내기 위함 : const_cast<int *>
reinterpret_cast : 포인터 형변환
모든 포인터들의 형변환을 허용함, (const 포인터 제외)
int iNumber= 60;
char* ptr = reinterpret_cast<char*> (&iNumber);
매우 위험한 형변환임. 굳이 쓰면 void* 에