dynamic_cast in C++

dynamic_cast in C++

foreword

The dynamic_cast operator involves object-oriented polymorphism and the state of the program at runtime, so it cannot be completely replaced by traditional conversion methods. Therefore, it is the most commonly used and indispensable operator. Like static_cast , the conversion of dynamic_cast also requires a certain relationship between the target type and the source object: an inheritance relationship. More precisely, dynamic_cast is used to check whether there is an inheritance relationship between the two. So the operator actually only accepts class conversions based on pointers and references to class objects. From this point of view, it seems that dynamic_cast is consistent with reinterpret_cast , but in fact, there are still big differences between them. quote

 If the conversion is successful, dynamic_casta new-type value will be returned. If the conversion fails and new-type is a pointer type, return that type 空指针. If the conversion fails and the new-type is a reference type, it will throw a handler that matches the std::bad_cast type 异常.

dynamic_cast

 dynamic_cast(expression)

Note:

 Only the following conversions can be done using dynamic_cast, unless those conversions discard constness or volatile.

  1. If the type of expression happens to be new-type or a less cv (constness and volatile) qualified version of new-type, the result is the value of expression, of type new-type. (In other words, dynamic_cast can be used to add constness or volatile. 隐式转换And static_castcan also perform this conversion)
  D* d1 = new D();
  D* d2 = dynamic_cast<D*>(d1);
  d2->hello();
  const D *d3 = dynamic_cast<const D *>(d1);
  1. If the value of expression is 空指针a value, the result is a new-type null pointer value.
   D *ptr = NULL;
   D* ptr2 = dynamic_cast<D*>(ptr);
   if(ptr2 == NULL){
    
    
      printf("ptr2 is NULL\n");
   }

console output

2) ptr2 is NULL

  1. If new-type is a pointer Baseor reference to and the type of expression is a pointer or Derivedreference to a unique, accessible base class of , then the result is a pointer to the Derived object pointed to or defined by expression A pointer or reference to the base class subobject of . (Note: implicit conversion and static_cast can also perform this conversion)BaseDerived

  1. If expression is a pointer to 多态类型and new-type is a pointer voidto, the result is a pointer to the derived 最底层object pointed to or referenced by expression.


5. If expression is 多态类型a pointer or reference to Base, and new-type is a pointer or reference to Derived, then execute 运行时检查. This should be the most used scenario of dynamic_cast:

  • a) If, in that object, expression is a pointer 公共基/reference to derived, and if there is only one object of derived type derived from the subobject pointed to/defined by expression, the result of the cast points/references to that derived object . (downcast')
D d;      // the most derived object
A &a = d; // upcast, dynamic_cast may be used, but unnecessary
[[maybe_unused]] D &new_d = dynamic_cast<D &>(a); // downcast
new_d.hello();
  • 公共基类b) Otherwise, if expression is a pointer or reference to the bottom-most derived object, and at the same time, the bottom-most derived object has a definite common base class of type derived, then the result of the conversion points to/ references derived . (sidecast)

    D d;      // the most derived object
    A &a = d; // upcast, dynamic_cast may be used, but unnecessary   
    [[maybe_unused]] B &new_b = dynamic_cast<B &>(a); // sidecast
    new_b.hello();
    
  • c) Otherwise, 运行时the check fails. If dynamic_cast is used on a pointer, a null pointer value of type new-type is returned. 异常If it is used for references, std::bad_cast is thrown .


6. When dynamic_cast is used in the constructor or destructor (directly or indirectly), the expression points to the current 构造/销毁object, and the object is considered to be the bottom-level derived object. The behavior if the new-type is not a pointer or reference to the constructor/destructor's own class or one of the base classes, 未定义6) in the example below

 Similar to other cast expressions, the result is:

  • If new-type is an lvalue reference type (expression must be an lvalue), the result is an lvalue,

  • If new-type is an rvalue reference type (expression can be an lvalue, or an rvalue (until c++17) must be a glvalue of a complete class type (since c++17)), then the result is an xvalue.

  • If new-type is a pointer type, it is a prvalue.

 For the definition of several values, please refer to https://cloud.tencent.com/developer/article/1493839

Example:

struct V
{
    
    
   virtual void f() {
    
    } // must be polymorphic to use runtime-checked dynamic_cast
};

struct A : virtual V
{
    
    
   void hello()
   {
    
    
        printf("hello, I am A\n");
   }
};

struct B : virtual V
{
    
    
   B(V *v, A *a)
   {
    
    
       	
        // casts during construction (see the call in the constructor of D below)
        dynamic_cast<B *>(v); // well-defined: v of type V*, V base of B, results in B*
        dynamic_cast<B *>(a); // undefined behavior: a has type A*, A not a base of B
   }
   void hello()
   {
    
    
        printf("hello, I am B\n");
   }
};

struct D : A, B
{
    
    
   //6)
   D() : B(static_cast<A *>(this), this) {
    
    }
   void hello(){
    
    
    printf("hello, I am D\n");
   }
};

struct Base
{
    
    
   virtual ~Base() {
    
    }
};

struct Derived : Base
{
    
    
   virtual void name() {
    
    }
};
void test_dynamic_cast(){
    
    

   D d;      // the most derived object
   A &a = d; // upcast, dynamic_cast may be used, but unnecessary

   [[maybe_unused]] D &new_d = dynamic_cast<D &>(a); // downcast
    new_d.hello();
   [[maybe_unused]] B &new_b = dynamic_cast<B &>(a); // sidecast
    new_b.hello();
   Base *b1 = new Base;
   if (Derived *d = dynamic_cast<Derived *>(b1); d != nullptr)
   {
    
    
        std::cout << "downcast from b1 to d successful\n";
        d->name(); // safe to call
   }

   Base *b2 = new Derived;
   if (Derived *d = dynamic_cast<Derived *>(b2); d != nullptr)
   {
    
    
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // safe to call
   }

   delete b1;
   delete b2;
}

console output

sh-4.4$ ./build/linux/x86_64/release/Class-convert 
hello, I am D
hello, I am B
downcast from b2 to d successful

Guess you like

Origin blog.csdn.net/dddgggd/article/details/129394181