dynamic_cast 연산자

피연산 expression 자를 형식 type-id의 개체로 변환합니다.

구문

dynamic_cast < type-id > ( expression )

설명

포인터 type-id 또는 이전에 정의한 클래스 형식에 대한 참조 또는 "void에 대한 포인터"여야 합니다. type-id이 포인터인 경우 expression의 형식은 포인터여야 하며 type-id이 참조인 경우에는 l 값이어야 합니다.

정적 및 동적 캐스팅 변환 간의 차이점과 각각을 사용하는 것이 적절한 경우의 설명은 static_cast 참조하세요.

관리 코드의 dynamic_cast 동작에는 다음과 같은 두 가지 주요 변경 내용이 있습니다.

  • dynamic_cast 상자 열거형의 기본 형식에 대한 포인터에 대한 포인터는 런타임에 실패하고 변환된 포인터 대신 0을 반환합니다.

  • dynamic_cast 는 값 형식에 대한 내부 포인터인 경우 type-id 더 이상 예외를 throw하지 않습니다. 대신 런타임에 캐스트가 실패합니다. 캐스트는 throw하는 대신 0 포인터 값을 반환합니다.

명확하게 액세스할 수 있는 직접 또는 간접 기본 클래스에 대한 포인터인 경우 type-id 형식 type-idexpression고유 하위 개체에 대한 포인터가 결과입니다. 예시:

// dynamic_cast_1.cpp
// compile with: /c
class B { };
class C : public B { };
class D : public C { };

void f(D* pd) {
   C* pc = dynamic_cast<C*>(pd);   // ok: C is a direct base class
                                   // pc points to C subobject of pd
   B* pb = dynamic_cast<B*>(pd);   // ok: B is an indirect base class
                                   // pb points to B subobject of pd
}

이 유형의 변환은 파생 클래스에서 파생된 클래스로 포인터를 클래스 계층 구조 위로 이동하기 때문에 "upcast"라고 합니다. 업캐스트는 암시적 변환입니다.

void*이면 type-id 실제 형식expression을 확인하기 위해 런타임 검사 만들어집니다. 결과는 .에서 가리키는 expression전체 개체에 대한 포인터입니다. 예시:

// dynamic_cast_2.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
   A* pa = new A;
   B* pb = new B;
   void* pv = dynamic_cast<void*>(pa);
   // pv now points to an object of type A

   pv = dynamic_cast<void*>(pb);
   // pv now points to an object of type B
}

그렇지 않은 경우 type-id 가리키는 개체를 가리키는 type-id형식으로 변환할 수 있는지 확인하기 위해 expression 런타임 검사 만들어void*집니다.

형식이 형식type-idexpression 기본 클래스인 경우 런타임 검사 실제로 형식type-id의 전체 개체를 가리키는지 expression 확인합니다. true이면 결과는 형식 type-id의 전체 개체에 대한 포인터입니다. 예시:

// dynamic_cast_3.cpp
// compile with: /c /GR
class B {virtual void f();};
class D : public B {virtual void f();};

void f() {
   B* pb = new D;   // unclear but ok
   B* pb2 = new B;

   D* pd = dynamic_cast<D*>(pb);   // ok: pb actually points to a D
   D* pd2 = dynamic_cast<D*>(pb2);   // pb2 points to a B not a D
}

이 유형의 변환은 지정된 클래스에서 파생된 클래스로 클래스 계층 구조 아래로 포인터를 이동하기 때문에 "downcast"라고 합니다.

여러 상속의 경우 모호성에 대한 가능성이 도입됩니다. 다음 그림에 표시된 클래스 계층 구조를 고려합니다.

CLR 형식 dynamic_cast 의 경우 변환을 암시적으로 수행할 수 있는 경우 no-op 또는 동적 검사 수행하고 변환이 실패하면 반환 nullptr 하는 MSIL isinst 명령이 발생합니다.

다음 샘플에서는 클래스가 특정 형식의 인스턴스인지 확인하는 데 사용합니다 dynamic_cast .

// dynamic_cast_clr.cpp
// compile with: /clr
using namespace System;

void PrintObjectType( Object^o ) {
   if( dynamic_cast<String^>(o) )
      Console::WriteLine("Object is a String");
   else if( dynamic_cast<int^>(o) )
      Console::WriteLine("Object is an int");
}

int main() {
   Object^o1 = "hello";
   Object^o2 = 10;

   PrintObjectType(o1);
   PrintObjectType(o2);
}

Diagram that shows multiple inheritance.

다이어그램은 A가 기본 클래스인 B의 기본 클래스인 클래스 계층 구조를 보여줍니다. A는 C에 대한 기본 클래스이기도 합니다. 이 클래스는 D. 클래스 D가 B와 C 모두에서 상속하는 기본 클래스입니다.

형식 D 의 개체에 대한 포인터를 안전하게 캐스팅 B 할 수 있습니다 C. 그러나 개체를 가리키 A 도록 캐스팅되는 경우 D 어떤 인스턴스가 A 발생합니까? 이로 인해 캐스팅 오류가 모호합니다. 이 문제를 해결하려면 두 개의 명확한 캐스트를 수행할 수 있습니다. 예시:

// dynamic_cast_4.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A {virtual void f();};
class D : public B, public C {virtual void f();};

void f() {
   D* pd = new D;
   A* pa = dynamic_cast<A*>(pd);   // C4540, ambiguous cast fails at runtime
   B* pb = dynamic_cast<B*>(pd);   // first cast to B
   A* pa2 = dynamic_cast<A*>(pb);   // ok: unambiguous
}

가상 기본 클래스를 사용할 때 추가 모호성을 도입할 수 있습니다. 다음 그림에 표시된 클래스 계층 구조를 고려합니다.

Diagram of a class hierarchy that shows virtual base classes.

다이어그램은 다음과 같이 정렬된 A, B, C, D 및 E 클래스를 보여 줍니다. 클래스 A는 B의 기본 클래스입니다. 클래스 C와 E는 각각 B에서 파생됩니다. 클래스 E는 클래스 A에서 상속되는 클래스 B에서 상속됩니다.

가상 기본 클래스를 보여 주는 클래스 계층 구조

이 계층 구조 A 에서는 가상 기본 클래스입니다. 클래스 E 인스턴스와 하위 개체 dynamic_cast 에 대한 포인터가 A 지정된 경우 모호성으로 인해 실패할 B 포인터에 대한 포인터입니다. 먼저 전체 E 개체로 다시 캐스팅한 다음, 명확한 방식으로 계층 구조를 백업하여 올바른 B 개체에 도달해야 합니다.

다음 그림에 표시된 클래스 계층 구조를 고려합니다.

Diagram of a class hierarchy that shows duplicate base classes.

다이어그램은 클래스 A, B, C, D 및 E가 다음과 같이 정렬된 것을 보여 줍니다. 클래스 B는 클래스 A에서 파생됩니다. 클래스 C는 클래스 A에서 파생됩니다. 클래스 D는 클래스 B에서 파생됩니다. 클래스 E는 클래스 A에서 파생되는 C 클래스에서 파생됩니다. 이 경우 중복 기본 클래스는 다른 모든 클래스에서 직접 또는 간접적으로 상속되는 클래스 A입니다. 클래스 A는 클래스 B 및 C에 의해 직접 상속되고, 클래스 B를 통해 클래스 D에 의해 간접적으로 상속되고, 클래스 C를 통해 E 클래스에 의해 간접적으로 상속되고, 클래스 B를 통해 클래스 D에서 간접적으로 상속됩니다.

중복된 기본 클래스를 보여 주는 클래스 계층 구조

하위 개체의 개체 E 와 하위 개체에 D 대한 포인터를 사용하여 하위 개체에서 D 가장 왼쪽 A 하위 개체로 이동하려면 세 가지 변환을 수행할 수 있습니다. 포인터에서 D 포인터로 dynamic_castE 변환한 다음 변환(또는 dynamic_cast 암시적 변환)을 대 EB변환하고 마지막으로 암시적 변환을 B 수행할 수 있습니다A. 예시:

// dynamic_cast_5.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {
   E* pe = dynamic_cast<E*>(pd);
   B* pb = pe;   // upcast, implicit conversion
   A* pa = pb;   // upcast, implicit conversion
}

연산자를 dynamic_cast 사용하여 "교차 캐스트"를 수행할 수도 있습니다. 동일한 클래스 계층 구조를 사용하면 전체 개체가 형식인 한 포인터를 하위 개체에서 B 하위 개체로 캐스팅할 D 수 있습니다 E.

교차 캐스트를 고려할 때 포인터에서 가장 왼쪽 A 하위 개체에 대한 포인터 D 로의 변환을 단 두 단계로 수행할 수 있습니다. 크로스 캐스트 D 를 수행할 수 있습니다. B그런 다음 암시적 변환을 B 수행합니다 A. 예시:

// dynamic_cast_6.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {
   B* pb = dynamic_cast<B*>(pd);   // cross cast
   A* pa = pb;   // upcast, implicit conversion
}

null 포인터 값은 대상 형식의 null 포인터 값으로 변환됩니다 dynamic_cast.

사용할 dynamic_cast < type-id > ( expression )때 안전하게 형식type-id으로 변환할 수 없는 경우 expression 런타임 검사 캐스팅이 실패합니다. 예시:

// dynamic_cast_7.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
   A* pa = new A;
   B* pb = dynamic_cast<B*>(pa);   // fails at runtime, not safe;
   // B not derived from A
}

포인터 형식으로 캐스팅하지 못한 값은 null 포인터입니다. 참조 형식에 실패한 캐스트는 bad_cast 예외throw합니다. 유효한 개체를 가리키거나 참조하지 않으면 expression 예외가 __non_rtti_object throw됩니다.

예외에 대한 설명은 typeid를 참조하세요.__non_rtti_object

예시

다음 샘플에서는 개체(구조체 C)에 대한 기본 클래스(구조체 A) 포인터를 만듭니다. 이는 가상 함수가 있다는 사실과 함께 런타임 다형성을 가능하게 합니다.

또한 이 샘플은 계층 구조에서 비가상 함수를 호출합니다.

// dynamic_cast_8.cpp
// compile with: /GR /EHsc
#include <stdio.h>
#include <iostream>

struct A {
    virtual void test() {
        printf_s("in A\n");
   }
};

struct B : A {
    virtual void test() {
        printf_s("in B\n");
    }

    void test2() {
        printf_s("test2 in B\n");
    }
};

struct C : B {
    virtual void test() {
        printf_s("in C\n");
    }

    void test2() {
        printf_s("test2 in C\n");
    }
};

void Globaltest(A& a) {
    try {
        C &c = dynamic_cast<C&>(a);
        printf_s("in GlobalTest\n");
    }
    catch(std::bad_cast) {
        printf_s("Can't cast to C\n");
    }
}

int main() {
    A *pa = new C;
    A *pa2 = new B;

    pa->test();

    B * pb = dynamic_cast<B *>(pa);
    if (pb)
        pb->test2();

    C * pc = dynamic_cast<C *>(pa2);
    if (pc)
        pc->test2();

    C ConStack;
    Globaltest(ConStack);

   // fails because B knows nothing about C
    B BonStack;
    Globaltest(BonStack);
}
in C
test2 in B
in GlobalTest
Can't cast to C

참고 항목

캐스팅 연산자
키워드