상속과 RTTI
함수가 인자로 기반 클래스의 포인터를 받으면
- 기반 클래스 뿐 아니라 모든 파생 클래스를 전달 받을 수 있다.
기반 클래스 포인터로 파생 클래스의 고유 멤버에 접근 할 수 없다.
- 파생클래스의 고유 멤버에 접근하려면 파생 클래스 타입으로 캐스팅 (다운 캐스팅, downcasting) 해야 한다.
#include <iostream>
#include <typeinfo>
class Animal {};
class Dog : public Animal
{
public:
int color;
};
void foo(Animal* p)
{
// p가 Dog 이라면
p->color = 10; // error
}
int main()
{
Animal a; foo(&a);
Dog d; foo(&d);
}
아래와 같이 p는 Animal 클래스 형태로 선언되었으므로 color 정보가 없다. 아래와 같은 에러를 만날 수 있다.
main.cpp:15:8: error: ‘class Animal’ has no member named ‘color’
15 | p->color = 10; // error
| ^~~~~
상속관계에서 사용하는 RTTI (typeid)
typeid
가상함수가 없는 객체 (non polymorphic type) 컴파일 시간에 포인터 타입으로 조사
가상함수가 있는 객체 (polymorphic type) 실행시간 타입 조사 (가상함수 테이블 등을 사용)
<잘못된 사용 방법> 아래의 경우 *p를 컴파일 시간에 조사해서 Animal 로 출력됨.
#include <iostream>
#include <typeinfo>
class Animal {};
class Dog : public Animal
{
public:
int color;
};
void foo(Animal* p)
{
const std::type_info& t = typeid(*p);
std::cout << t.name() << std::endl;
}
int main()
{
Animal a; foo(&a);
Dog d; foo(&d);
}
실행시간 타입 조사를 위해 가상함수로 선언 되어 있어야 한다.
#include <iostream>
#include <typeinfo>
class Animal
{
public:
virtual ~Animal() {} // 기반 클래스이 소멸자는 반드시 가상함수여야 한다.
};
class Dog : public Animal
{
public:
int color;
};
void foo(Animal* p)
{
//const std::type_info& t = typeid(p);
const std::type_info& t = typeid(*p);
std::cout << t.name() << std::endl;
if ( typeid(*p) == typeid(Dog))
{
Dog* pDog = static_cast<Dog*>(p); // 다운 캐스팅
pDog->color = 10; // 멤버 함수 접근 가능
std::cout << "Dog" << std::endl;
}
}
int main()
{
Animal a; foo(&a);
Dog d; foo(&d);
}
upcasting VS downcasting
upcasting : 파생 클래스 포인터를 기반 클래스 타입으로 캐스팅 하는 것 (항상 안전함)
downcasting : 기반 클래스 포인터를 파생클래스 타입으로 캐스팅하는 것 (안전하지 않을 수도 있다.)
downcasting과 캐스팅 연산자
static_cast : 잘못된 downcasting 조사할 수 없다.
- 단, 컴파일 시간에 캐스팅을 수행하므로 오버헤드가 없다.
dynamic_cast : 잘못된 downcasting 을 하면 0을 반환 한다.
- 실행시간에 캐스팅을 수행하므로 약간의 오버헤드가 있다.
#include <iostream>
#include <typeinfo>
class Animal
{
public:
virtual ~Animal() {}
};
class Dog : public Animal
{
public:
int color;
};
void foo(Animal* p)
{
Dog* pD = static_cast<Dog*>(p);
std::cout << "1) " << pD << std::endl;
// 잘못된 downcasting을 조사할 수 없다.
Dog* pDog = dynamic_cast<Dog*>(p);
if ( pDog != 0 )
{
std::cout << "2-1) " << pDog << ", color:" << pDog->color << std::endl;
pDog->color = 10;
std::cout << "2-2) " << pDog << ", color:" << pDog->color << std::endl;
}
std::cout << "2) " << pDog << std::endl;
}
int main()
{
Animal a; foo(&a);
std::cout << "==============================" << std::endl;
Dog d; foo(&d);
}
'C++' 카테고리의 다른 글
[C++] 연산자 재정의 (operator overloading) (0) | 2022.01.01 |
---|---|
[C++] 다중 상속 (multiple inheritance) (0) | 2021.12.31 |
[C++] RTTI (Run Time Type Information) (0) | 2021.12.29 |
[C++] 추상 클래스 (abstract class), 인터페이스(interface) (0) | 2021.12.28 |
[C++] virtual function (가상 함수), function override(오버라이드) (0) | 2021.08.28 |
댓글