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-id
의 expression
고유 하위 개체에 대한 포인터가 결과입니다. 예시:
// 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-id
의 expression
기본 클래스인 경우 런타임 검사 실제로 형식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);
}
다이어그램은 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
}
가상 기본 클래스를 사용할 때 추가 모호성을 도입할 수 있습니다. 다음 그림에 표시된 클래스 계층 구조를 고려합니다.
다이어그램은 다음과 같이 정렬된 A, B, C, D 및 E 클래스를 보여 줍니다. 클래스 A는 B의 기본 클래스입니다. 클래스 C와 E는 각각 B에서 파생됩니다. 클래스 E는 클래스 A에서 상속되는 클래스 B에서 상속됩니다.
가상 기본 클래스를 보여 주는 클래스 계층 구조
이 계층 구조 A
에서는 가상 기본 클래스입니다. 클래스 E
인스턴스와 하위 개체 dynamic_cast
에 대한 포인터가 A
지정된 경우 모호성으로 인해 실패할 B
포인터에 대한 포인터입니다. 먼저 전체 E
개체로 다시 캐스팅한 다음, 명확한 방식으로 계층 구조를 백업하여 올바른 B
개체에 도달해야 합니다.
다음 그림에 표시된 클래스 계층 구조를 고려합니다.
다이어그램은 클래스 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_cast
E
변환한 다음 변환(또는 dynamic_cast
암시적 변환)을 대 E
로 B
변환하고 마지막으로 암시적 변환을 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
참고 항목
피드백
https://aka.ms/ContentUserFeedback
출시 예정: 2024년 내내 콘텐츠에 대한 피드백 메커니즘으로 GitHub 문제를 단계적으로 폐지하고 이를 새로운 피드백 시스템으로 바꿀 예정입니다. 자세한 내용은 다음을 참조하세요.다음에 대한 사용자 의견 제출 및 보기