C ++의 dynamic_cast 및 static_cast
dynamic_castC ++ 의 키워드 와 혼동됩니다 .
struct A {
virtual void f() { }
};
struct B : public A { };
struct C { };
void f () {
A a;
B b;
A* ap = &b;
B* b1 = dynamic_cast<B*> (&a); // NULL, because 'a' is not a 'B'
B* b2 = dynamic_cast<B*> (ap); // 'b'
C* c = dynamic_cast<C*> (ap); // NULL.
A& ar = dynamic_cast<A&> (*ap); // Ok.
B& br = dynamic_cast<B&> (*ap); // Ok.
C& cr = dynamic_cast<C&> (*ap); // std::bad_cast
}
정의는 말한다 :
dynamic_cast키워드는 캐스트의 유효성을 보장하기 위해 런타임 검사를 수행, 다른 하나 개의 포인터 또는 참조 유형에서 데이텀 캐스트
dynamic_cast사물을 더 잘 이해할 수 있도록 C 로 동등한 C ++를 작성할 수 있습니까?
여기에 개요입니다 static_cast<>그리고 dynamic_cast<>그들은 포인터에 특별히을 관련이있다. 이것은 101 수준의 런 다운이며 모든 복잡한 사항을 다루지는 않습니다.
static_cast <유형 *> (ptr)
이것은 포인터를 가져 와서 ptr포인터 타입으로 안전하게 캐스트하려고합니다 Type*. 이 캐스트는 컴파일 타임에 수행됩니다. 유형 유형이 관련된 경우에만 캐스트를 수행합니다. 유형이 관련이 없으면 컴파일러 오류가 발생합니다. 예를 들면 다음과 같습니다.
class B {};
class D : public B {};
class X {};
int main()
{
D* d = new D;
B* b = static_cast<B*>(d); // this works
X* x = static_cast<X*>(d); // ERROR - Won't compile
return 0;
}
dynamic_cast <유형 *> (ptr)
이것은 포인터를 다시 가져 와서 ptr타입 포인터로 안전하게 캐스트합니다 Type*. 그러나이 캐스트는 컴파일 타임이 아니라 런타임에 실행됩니다. 이것은 런타임 캐스트이므로 다형성 클래스와 결합 할 때 특히 유용합니다. 실제로, certian의 경우 캐스트가 합법적이 려면 클래스 가 다형성 이어야합니다 .
캐스트는 기본에서 파생으로 (B2D) 또는 파생에서 기본으로 (D2B) 두 방향 중 하나로 진행할 수 있습니다. D2B 캐스트가 런타임에 작동하는 방식을 보는 것은 간단합니다. 하나는 ptr에서 파생 된 Type또는 아니었다. D2B dynamic_cast <> s의 경우 규칙은 간단합니다. 다른 것에 무언가를 캐스트하려고 할 수 있으며 ptr실제로에서 파생 된 경우에서 포인터를 다시 Type얻을 수 Type*있습니다 dynamic_cast. 그렇지 않으면 NULL 포인터가 표시됩니다.
그러나 B2D 캐스트는 조금 더 복잡합니다. 다음 코드를 고려하십시오.
#include <iostream>
using namespace std;
class Base
{
public:
virtual void DoIt() = 0; // pure virtual
virtual ~Base() {};
};
class Foo : public Base
{
public:
virtual void DoIt() { cout << "Foo"; };
void FooIt() { cout << "Fooing It..."; }
};
class Bar : public Base
{
public :
virtual void DoIt() { cout << "Bar"; }
void BarIt() { cout << "baring It..."; }
};
Base* CreateRandom()
{
if( (rand()%2) == 0 )
return new Foo;
else
return new Bar;
}
int main()
{
for( int n = 0; n < 10; ++n )
{
Base* base = CreateRandom();
base->DoIt();
Bar* bar = (Bar*)base;
bar->BarIt();
}
return 0;
}
main()어떤 종류의 객체 CreateRandom()가 반환 되는지 알 수 없으므로 C 스타일 캐스트 Bar* bar = (Bar*)base;는 유형 안전하지 않습니다. 이 문제를 어떻게 해결할 수 있습니까? 한 가지 방법은 부울 같은 기능을 추가하는 것입니다 AreYouABar() const = 0;기본 클래스에 반환 true에서 Bar와 false에서 Foo. 그러나 다른 방법이 있습니다 : use dynamic_cast<>:
int main()
{
for( int n = 0; n < 10; ++n )
{
Base* base = CreateRandom();
base->DoIt();
Bar* bar = dynamic_cast<Bar*>(base);
Foo* foo = dynamic_cast<Foo*>(base);
if( bar )
bar->BarIt();
if( foo )
foo->FooIt();
}
return 0;
}
캐스트는 런타임에 실행되며 객체를 쿼리하여 (지금 방법에 대해 걱정할 필요가 없음) 원하는 유형인지 묻습니다. 그렇다면 dynamic_cast<Type*>포인터를 반환합니다. 그렇지 않으면 NULL을 반환합니다.
이 base-to-derived 캐스팅이 dynamic_cast<>, Base, Foo 및 Bar를 사용하여 작동 하려면 표준에서 다형성 유형을 호출해야합니다 . 다형성 유형이 되려면 클래스에 virtual함수가 하나 이상 있어야합니다 . 클래스가 다형성 유형이 아닌 경우 기본에서 파생 된 사용은 dynamic_cast컴파일되지 않습니다. 예:
class Base {};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // ERROR - Won't compile
return 0;
}
가상 dtor와 같은 기본에 가상 함수를 추가하면 기본 및 Der 다형성 유형이 모두 생성됩니다.
class Base
{
public:
virtual ~Base(){};
};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // OK
return 0;
}
직접 롤링 한 RTTI를 구현하지 않고 시스템을 우회하지 않으면 dynamic_castC ++ 사용자 수준 코드로 직접 구현할 수 없습니다 . dynamic_castC ++ 구현의 RTTI 시스템과 밀접한 관련이 있습니다.
그러나 RTTI를 이해하는 데 도움이 dynamic_cast되도록 <typeinfo>헤더와 typeid연산자를 자세히 읽어보십시오 . 그러면 현재 보유하고있는 객체에 해당하는 유형 정보가 반환되며 이러한 유형 정보 객체에서 다양한 (제한적) 사항을 조회 할 수 있습니다.
C의 코드보다 영어 정의로 충분하다고 생각합니다.
파생 클래스 Derived가있는 Base 클래스가 주어지면 dynamic_cast실제로 가리키는 실제 개체가 실제로 Derived 개체 인 경우에만 Base 포인터를 Derived 포인터로 변환합니다.
class Base { virtual ~Base() {} };
class Derived : public Base {};
class Derived2 : public Base {};
class ReDerived : public Derived {};
void test( Base & base )
{
dynamic_cast<Derived&>(base);
}
int main() {
Base b;
Derived d;
Derived2 d2;
ReDerived rd;
test( b ); // throw: b is not a Derived object
test( d ); // ok
test( d2 ); // throw: d2 is not a Derived object
test( rd ); // ok: rd is a ReDerived, and thus a derived object
}
이 예에서 test다른 객체를에 대한 참조에 바인딩 하는 호출 Base입니다. 내부적으로 기준이되는 downcasted 에 대한 참조로 Derived형태 보증 방법 : 내리 뜬 만 참조 된 개체가 참의 인스턴스 그 경우에 성공할 것이다 Derived.
다음은 dynamic_cast유형 검사 측면 에서 C ++에서 얻는 것과 실제로 가깝지는 않지만 목적을 조금 더 잘 이해하는 데 도움이 될 것입니다.
struct Animal // Would be a base class in C++
{
enum Type { Dog, Cat };
Type type;
};
Animal * make_dog()
{
Animal * dog = new Animal;
dog->type = Animal::Dog;
return dog;
}
Animal * make_cat()
{
Animal * cat = new Animal;
cat->type = Animal::Cat;
return cat;
}
Animal * dyn_cast(AnimalType type, Animal * animal)
{
if(animal->type == type)
return animal;
return 0;
}
void bark(Animal * dog)
{
assert(dog->type == Animal::Dog);
// make "dog" bark
}
int main()
{
Animal * animal;
if(rand() % 2)
animal = make_dog();
else
animal = make_cat();
// At this point we have no idea what kind of animal we have
// so we use dyn_cast to see if it's a dog
if(dyn_cast(Animal::Dog, animal))
{
bark(animal); // we are sure the call is safe
}
delete animal;
}
A dynamic_cast는 RTTI를 사용하여 유형 검사를 수행합니다 . 실패하면 예외 (참조를 제공 한 경우) 또는 포인터를 제공하면 NULL이 발생합니다.
먼저 C 용어로 동적 캐스트를 설명하려면 C로 클래스를 나타내야합니다. 가상 함수가있는 클래스는 가상 함수에 대한 "VTABLE"포인터를 사용합니다. 주석은 C ++입니다. 컴파일 오류를 다시 포맷하고 수정하십시오 ...
// class A { public: int data; virtual int GetData(){return data;} };
typedef struct A { void**vtable; int data;} A;
int AGetData(A*this){ return this->data; }
void * Avtable[] = { (void*)AGetData };
A * newA() { A*res = malloc(sizeof(A)); res->vtable = Avtable; return res; }
// class B : public class A { public: int moredata; virtual int GetData(){return data+1;} }
typedef struct B { void**vtable; int data; int moredata; } B;
int BGetData(B*this){ return this->data + 1; }
void * Bvtable[] = { (void*)BGetData };
B * newB() { B*res = malloc(sizeof(B)); res->vtable = Bvtable; return res; }
// int temp = ptr->GetData();
int temp = ((int(*)())ptr->vtable[0])();
그런 다음 동적 캐스트는 다음과 같습니다.
// A * ptr = new B();
A * ptr = (A*) newB();
// B * aB = dynamic_cast<B>(ptr);
B * aB = ( ptr->vtable == Bvtable ? (B*) aB : (B*) 0 );
C에는 클래스가 없으므로 해당 언어로 dynamic_cast를 작성할 수 없습니다. C 구조에는 메소드가 없으므로 (가상적으로 가상 메소드가 없음) "동적"이 없습니다.
아니, 쉽게 컴파일러는 모든 클래스에 고유 한 ID를 할당합니다.이 정보는 모든 객체 인스턴스에서 참조되며 런타임시 동적 캐스트가 유효한지 확인하기 위해 검사됩니다. 이 정보와 연산자를 사용하여 해당 기본 클래스에서 런타임 검사를 수행하는 표준 기본 클래스를 만들 수 있으며 파생 클래스는 클래스 계층에서 해당 클래스의 위치를 기본 클래스에 알리고 해당 클래스의 모든 인스턴스는 다음을 통해 런타임 캐스팅 가능합니다. 당신의 작업.
편집하다
다음은 하나의 기술을 보여주는 구현입니다. 컴파일러가 이와 같은 것을 사용한다고 주장하지는 않지만 개념을 보여줍니다.
class SafeCastableBase
{
public:
typedef long TypeID;
static TypeID s_nextTypeID;
static TypeID GetNextTypeID()
{
return s_nextTypeID++;
}
static TypeID GetTypeID()
{
return 0;
}
virtual bool CanCastTo(TypeID id)
{
if (GetTypeID() != id) { return false; }
return true;
}
template <class Target>
static Target *SafeCast(SafeCastableBase *pSource)
{
if (pSource->CanCastTo(Target::GetTypeID()))
{
return (Target*)pSource;
}
return NULL;
}
};
SafeCastableBase::TypeID SafeCastableBase::s_nextTypeID = 1;
class TypeIDInitializer
{
public:
TypeIDInitializer(SafeCastableBase::TypeID *pTypeID)
{
*pTypeID = SafeCastableBase::GetNextTypeID();
}
};
class ChildCastable : public SafeCastableBase
{
public:
static TypeID s_typeID;
static TypeID GetTypeID()
{
return s_typeID;
}
virtual bool CanCastTo(TypeID id)
{
if (GetTypeID() != id) { return SafeCastableBase::CanCastTo(id); }
return true;
}
};
SafeCastableBase::TypeID ChildCastable::s_typeID;
TypeIDInitializer ChildCastableInitializer(&ChildCastable::s_typeID);
class PeerChildCastable : public SafeCastableBase
{
public:
static TypeID s_typeID;
static TypeID GetTypeID()
{
return s_typeID;
}
virtual bool CanCastTo(TypeID id)
{
if (GetTypeID() != id) { return SafeCastableBase::CanCastTo(id); }
return true;
}
};
SafeCastableBase::TypeID PeerChildCastable::s_typeID;
TypeIDInitializer PeerChildCastableInitializer(&PeerChildCastable::s_typeID);
int _tmain(int argc, _TCHAR* argv[])
{
ChildCastable *pChild = new ChildCastable();
SafeCastableBase *pBase = new SafeCastableBase();
PeerChildCastable *pPeerChild = new PeerChildCastable();
ChildCastable *pSameChild = SafeCastableBase::SafeCast<ChildCastable>(pChild);
SafeCastableBase *pBaseToChild = SafeCastableBase::SafeCast<SafeCastableBase>(pChild);
ChildCastable *pNullDownCast = SafeCastableBase::SafeCast<ChildCastable>(pBase);
SafeCastableBase *pBaseToPeerChild = SafeCastableBase::SafeCast<SafeCastableBase>(pPeerChild);
ChildCastable *pNullCrossCast = SafeCastableBase::SafeCast<ChildCastable>(pPeerChild);
return 0;
}
dynamic_cast uses RTTI. It can slow down your application, you can use modification of the visitor design pattern to achieve downcasting without RTTI http://arturx64.github.io/programming-world/2016/02/06/lazy-visitor.html
static_cast< Type* >(ptr)
static_cast in C++ can be used in scenarios where all type casting can be verified at compile time.
dynamic_cast< Type* >(ptr)
dynamic_cast in C++ can be used to perform type safe down casting. dynamic_cast is run time polymorphism. The dynamic_cast operator, which safely converts from a pointer (or reference) to a base type to a pointer (or reference) to a derived type.
eg 1:
#include <iostream>
using namespace std;
class A
{
public:
virtual void f(){cout << "A::f()" << endl;}
};
class B : public A
{
public:
void f(){cout << "B::f()" << endl;}
};
int main()
{
A a;
B b;
a.f(); // A::f()
b.f(); // B::f()
A *pA = &a;
B *pB = &b;
pA->f(); // A::f()
pB->f(); // B::f()
pA = &b;
// pB = &a; // not allowed
pB = dynamic_cast<B*>(&a); // allowed but it returns NULL
return 0;
}
For more information click here
eg 2:
#include <iostream>
using namespace std;
class A {
public:
virtual void print()const {cout << " A\n";}
};
class B {
public:
virtual void print()const {cout << " B\n";}
};
class C: public A, public B {
public:
void print()const {cout << " C\n";}
};
int main()
{
A* a = new A;
B* b = new B;
C* c = new C;
a -> print(); b -> print(); c -> print();
b = dynamic_cast< B*>(a); //fails
if (b)
b -> print();
else
cout << "no B\n";
a = c;
a -> print(); //C prints
b = dynamic_cast< B*>(a); //succeeds
if (b)
b -> print();
else
cout << "no B\n";
}
참고URL : https://stackoverflow.com/questions/2253168/dynamic-cast-and-static-cast-in-c
'Programming' 카테고리의 다른 글
| 루비 수면 또는 1 초 미만 지연? (0) | 2020.06.15 |
|---|---|
| C의 문자열에 하위 문자열이 있는지 확인 (0) | 2020.06.13 |
| 기본 HTML / CSS 링크 색상은 무엇입니까? (0) | 2020.06.13 |
| ActiveRecord 속성 메소드 대체 (0) | 2020.06.13 |
| Google지도에 영향을주는 Twitter 부트 스트랩 CSS (0) | 2020.06.13 |