Shape라는 parent 클래스가 있고 그 하위로 Triangle, Rectangle, Pentagon이라는 클래스가 있다고 가정합니다.
struct Shape {};struct Triangle : public Shape {};struct Rectangle : public Shape {};struct Pentagon : public Shape {};
object의 type을 찾아 내어 적당한 처리를 하는 방법 중의 가장 대표적인 예가 바로 dynamic_cast를 사용하는 것입니다(물론 클래스 내부에는 virtual function이 최소 하나 이상 있음을 가정합니다). 그런데 dynamic_cast는 multiple inheritance까지 처리해야 하므로 내부적으로 복잡한 연산을 수행하게 됩니다.
void checkShape(Shape* shape) {if ((dynamic_cast<Triangle*>(shape)) != nullptr) cout << "This is a triangle\n";else if ((dynamic_cast<Rectangle*>(shape)) != nullptr) cout << "This is a rectangle\n";else if ((dynamic_cast<Pentagon*>(shape)) != nullptr) cout << "This is a pentagon\n";else cout << "None of them\n";}
두 번째 방식으로 typeid라는 operator를 이용하여 처리할 수도 있습니다.
void checkShape2(Shape* shape) {const std::type_info& ti = typeid(*shape);if (ti == typeid(Triangle)) cout << "This is a triangle\n";else if (ti == typeid(Rectangle)) cout << "This is a rectangle\n";else if (ti == typeid(Pentagon)) cout << "This is a pentagon\n";else cout << "None of them\n";}
그런데, type_info에서 형 비교를 할 때에는 == operator를 사용해야 하고, == operator 내부에서는 strcmp 류의 함수가 호출이 됩니다. 클래스 명이 길면 그만큼 속도가 걸린다는 얘기.
class type_info {...
bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT{
return ((__name == __arg.__name)|| (__name[0] != '*' &&__builtin_strcmp (__name, __arg.__name) == 0));}
...
}
마지막으로 constexpr specifier를 이용하여 다음과 같이 사용할 수 있습니다. 아래 코드의 모든 클래스의 id()라는 function에서 반환하는 값은 compile time에 결정이 되지 runtime에 결정이 되는 것이 아닙니다. checkShape3 function의 switch 내부에서 함수의 실행 결과를 case의 value로 사용할 수 있는 것도 이러한 이유때문입니다.
struct Shape {static constexpr uint32_t const_hash(const char *p) {return *p ? static_cast<uint32_t>(*p) + 33 * const_hash(p + 1) : 5381;}
virtual uint32_t id() { return const_hash("Shape"); }};struct Triangle : public Shape {uint32_t id() override { return const_hash("Triangle"); }};struct Rectangle : public Shape {uint32_t id() override { return const_hash("Rectangle"); }};struct Pentagon : public Shape {uint32_t id() override { return const_hash("Pentagon"); }};void checkShape3(Shape* shape) {uint32_t id = shape->id();switch (id) {case Shape::const_hash("Triangle"): cout << "This is a triangle\n"; break;case Shape::const_hash("Rectangle"): cout << "This is a Rectangle\n"; break;case Shape::const_hash("Pentagon"): cout << "This is a Pentagon\n"; break;default: cout << "None of them"; break;}
}
결론적으로 checkShape3 function에서는 모든 값이 compile time에 결정되어 고정값으로 변환되어 컴파일이 되기 때문에 dynamic_cast를 사용하기 혹은 typeid를 사용하기보다 constexpr 함수를 사용하는 것이 속도상으로도 많은 이득이 발생합니다.
[download]