首页 > 编程语言 >c++ dynamic_cast 实现原理

c++ dynamic_cast 实现原理

时间:2022-10-13 17:56:00浏览次数:66  
标签:info dst dynamic c++ cast static type ptr

gcc

__dynamic_cast (const void *src_ptr,    // 对象指针
                const __class_type_info *src_type, // 源类型
                const __class_type_info *dst_type, // 目标类型,(the "T" in "dynamic_cast<T>(v)")
                ptrdiff_t src2dst) // 偏移量,
  {
  // 检查指针是否为空
  if (__builtin_expect(!src_ptr, 0))
    return NULL; // Handle precondition violations gracefully.
  // 虚函数表
  const void *vtable = *static_cast <const void *const *> (src_ptr);
  // 虚函数表头
  const vtable_prefix *prefix =
    (adjust_pointer <vtable_prefix>
     (vtable,  -ptrdiff_t (offsetof (vtable_prefix, origin))));
  // 继承类
  const void *whole_ptr =
      adjust_pointer <void> (src_ptr, prefix->whole_object);
  const __class_type_info *whole_type = prefix->whole_type;
  __class_type_info::__dyncast_result result;

  // 继承类的虚函数表
  const void *whole_vtable = *static_cast <const void *const *> (whole_ptr);
  const vtable_prefix *whole_prefix =
    (adjust_pointer <vtable_prefix>
     (whole_vtable, -ptrdiff_t (offsetof (vtable_prefix, origin))));
  // src 是一个单独的基类,不能转成 dst
  if (whole_prefix->whole_type != whole_type)
    return NULL;

  // 可以直接转换
  if (src2dst >= 0
      && src2dst == -prefix->whole_object
      && *whole_type == *dst_type)
    return const_cast <void *> (whole_ptr);

  whole_type->__do_dyncast (src2dst, __class_type_info::__contained_public,
                            dst_type, whole_ptr, src_type, src_ptr, result);
  if (!result.dst_ptr)
    return NULL;
  if (contained_public_p (result.dst2src))
    // src 是 dst 的 public 基类
    return const_cast <void *> (result.dst_ptr);
  if (contained_public_p (__class_type_info::__sub_kind
			  (result.whole2src & result.whole2dst)))
    // Both src and dst are known to be public bases of whole. Found a valid
    // cross cast.
    return const_cast <void *> (result.dst_ptr);
  if (contained_nonvirtual_p (result.whole2src))
    // Src is known to be a non-public nonvirtual base of whole, and not a
    // base of dst. Found an invalid cross cast, which cannot also be a down
    // cast
    return NULL;
  if (result.dst2src == __class_type_info::__unknown)
    result.dst2src = dst_type->__find_public_src (src2dst, result.dst_ptr,
                                                  src_type, src_ptr);
  if (contained_public_p (result.dst2src))
    // Found a valid down cast
    return const_cast <void *> (result.dst_ptr);
  // Must be an invalid down cast, or the cross cast wasn't bettered
  return NULL;
}

clang

__dynamic_cast(const void *static_ptr, const __class_type_info *static_type,
               const __class_type_info *dst_type,
               std::ptrdiff_t src2dst_offset) {
    // Possible future optimization:  Take advantage of src2dst_offset

    // Get (dynamic_ptr, dynamic_type) from static_ptr
    void **vtable = *static_cast<void ** const *>(static_ptr);
    ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
    const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
    const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);

    // Initialize answer to nullptr.  This will be changed from the search
    //    results if a non-null answer is found.  Regardless, this is what will
    //    be returned.
    const void* dst_ptr = 0;
    // Initialize info struct for this search.
    __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};

    // Find out if we can use a giant short cut in the search
    if (is_equal(dynamic_type, dst_type, false))
    {
        // Using giant short cut.  Add that information to info.
        info.number_of_dst_type = 1;
        // Do the  search
        dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
#ifdef _LIBCXX_DYNAMIC_FALLBACK
        // The following if should always be false because we should definitely
        //   find (static_ptr, static_type), either on a public or private path
        if (info.path_dst_ptr_to_static_ptr == unknown)
        {
            // We get here only if there is some kind of visibility problem
            //   in client code.
            syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
                    "should have public visibility. At least one of them is hidden. %s"
                    ", %s.\n", static_type->name(), dynamic_type->name());
            // Redo the search comparing type_info's using strcmp
            info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
            info.number_of_dst_type = 1;
            dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
        }
#endif  // _LIBCXX_DYNAMIC_FALLBACK
        // Query the search.
        if (info.path_dst_ptr_to_static_ptr == public_path)
            dst_ptr = dynamic_ptr;
    }
    else
    {
        // Not using giant short cut.  Do the search
        dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
 #ifdef _LIBCXX_DYNAMIC_FALLBACK
        // The following if should always be false because we should definitely
        //   find (static_ptr, static_type), either on a public or private path
        if (info.path_dst_ptr_to_static_ptr == unknown &&
            info.path_dynamic_ptr_to_static_ptr == unknown)
        {
            syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
                            "has hidden visibility or is defined in more than one translation "
                            "unit. They should all have public visibility. "
                            "%s, %s, %s.\n", static_type->name(), dynamic_type->name(),
                    dst_type->name());
            // Redo the search comparing type_info's using strcmp
            info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
            dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
        }
#endif  // _LIBCXX_DYNAMIC_FALLBACK
        // Query the search.
        switch (info.number_to_static_ptr)
        {
        case 0:
            if (info.number_to_dst_ptr == 1 &&
                    info.path_dynamic_ptr_to_static_ptr == public_path &&
                    info.path_dynamic_ptr_to_dst_ptr == public_path)
                dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
            break;
        case 1:
            if (info.path_dst_ptr_to_static_ptr == public_path ||
                   (
                       info.number_to_dst_ptr == 0 &&
                       info.path_dynamic_ptr_to_static_ptr == public_path &&
                       info.path_dynamic_ptr_to_dst_ptr == public_path
                   )
               )
                dst_ptr = info.dst_ptr_leading_to_static_ptr;
            break;
        }
    }
    return const_cast<void*>(dst_ptr);
}

标签:info,dst,dynamic,c++,cast,static,type,ptr
From: https://www.cnblogs.com/miyanyan/p/16789112.html

相关文章

  • c++ deque
    https://blog.csdn.net/WL0616/article/details/123187849?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-......
  • C++-string常用函数整理(建议收藏)
    https://zhaitianbao.blog.csdn.net/article/details/118993685?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST......
  • C++入门(上)
    ......
  • 安装pyflink1.15.2报错[gcc: error: unrecognized command line option '-std=c++14']
    问题描述:安装一些pyflink1.15.2时报错:gcc:error:unrecognizedcommandlineoption‘-std=c++14’ 解决方案升级gcc版本为5.2.0升级g++版本为5.2.0实施步骤cd/us......
  • 史上最全C/C++思维导图,B站疯传,快收藏!!(附配套学习视频)
    ​​B站最好的的C语言视频教程​​C++重点知识整理(导图在最下面)入门小知识命名空间概念:命名空间是新定义一个作用域,里面可以放函数,变量,定义类等,主要用来防止命名冲突实现nam......
  • C++ split string via delimeter
    #pragmaonce#pragmacomment(lib,"rpcrt4.lib")#include<Windows.h>#include<rpcdce.h>#include<iostream>#include<string>#include<vector>usingnames......
  • C++ 使用栈求解中缀、后缀表达式的值
    1.前言表达式求值对于有知识积累的你而言,可以通过认知,按运算符的优先级进行先后运算。但对计算机而言,表达式仅是一串普通的信息而已,需要通过编码的方式告诉计算机运算法......
  • [翻译] 关于UE的C++
    最近开始学习虚幻引擎使用C++来开发所以看了眼社区上面的一篇文章,就借助翻译软件翻译下来看看。UnrealC++学习“UnrealC++”可能比你想象的要容易得多,它已经接近自定......
  • [翻译] Unreal C++集成开发环境的选择与准备
    Choosing&PreparingIntegratedDevelopmentEnvironmentforUnrealC++要高效地使用UnrealC++,您需要做些什么?目前,虚拟引擎支持的集成开发环境很少。Rider虚幻引......
  • vscode配置c++环境(超简单)
    vscode配置c++环境(超简单)超简单!!!配置c++最麻烦的就是mingw的环境,有很多不同的版本,很杂乱,这里我们用最简单的办法展示。下载一个devc++。如果你问我,为什么下了devc++还......