首页 > 解决方案 > 尽管调用是在类型完整的地方完成的,但对类模板参数的 Dynamic_casting 会给出不完整的类型错误

问题描述

这是问题的代码:https
://godbolt.org/z/hK33nP6dT 下面的代码 片段还不够,完整的问题示例代码在那个 godbolt 链接中。

这是错误:

[ 33%] Building CXX object CMakeFiles/test.dir/main.cpp.o
In file included from /app/container.h:3,
                 from /app/main.cpp:3:
base.h: In instantiation of 'bool DerivedChecker<T>::IsValid(const BaseClass*) [with T = DerivedClass]':
base.h:13:7:   required from here
base.h:15:10: error: cannot 'dynamic_cast' 'base' (of type 'const struct BaseClass*') to type 'const struct DerivedClass*' (target is not pointer or reference to complete type)
   15 |   return dynamic_cast<const T*>(base) != nullptr;
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

我的总体目标是将 a 传递给BaseClass*函数IsValid并尝试dynamic_cast将该指针指向某个模板化类型 T。然后如果可能返回 true,如果失败则返回dynamic_castfalse 。dynamic_cast我只想看看传入的BaseClass*指针是否可以转换为模板类型 T。

问题是dynamic_cast由于某种原因类型不完整,即使我是IsValid从代码中具有完整类型的位置进行调用的。我想构造我的代码,以便dynamic_cast确实具有完整的类型,从而消除错误。

我需要DerivedChecker在其模板类型被前向声明(不完整)的地方声明对象,然后在模板类型完整的地方IsValid通过它们的基础虚拟调用。BaseChecker所以一般的想法是在各种头文件中前向声明的类型用作模板参数DerivedChecker

class DerivedClass; //forward declared, incomplete type
BaseChecker* checker = new DerivedChecker<DerivedClass>(); //forward declared type used as template parameter, storing as a pointer to BaseChecker and using a virtual call through it later

然后在他们各自的 .cpp 文件中,我包含完成这些类型的标题,然后调用IsValid

class DerivedClass : public BaseClass {}; //defined, complete class
checker->IsValid(new BaseClass()); //virtual call to DerivedChecker<DerivedClass>::IsValid

这必须在不同的头文件和编译单元中完成;我不能只是将所有这些东西粉碎到一个头文件/cpp 文件中,因为DerivedChecker将在许多地方使用许多不同的模板类型。

在我的示例中,我使用了在 中声明的前向DerivedClass,然后在对 . 的虚拟调用之前container.h完全定义了它。因此,当进行虚拟调用时, ,是完全定义的,但仍然抛出“目标不是完整类型的指针或引用”错误。container.cppDerivedChecker<DerivedClass>::IsValidIsValidDerivedChecker<DerivedClass>DerivedClassdynamic_cast

在示例代码中,base.h包含BaseCheckerDerivedChecker作为BaseClass参数的IsValid

container.h是 的常见用例DerivedChecker: 具有DerivedChecker字段的某个类(在本例中为 class Container),具有 in 中使用的模板类型的前向声明DerivedChecker(在本例中,DerivedChecker<DerivedClass>DerivedClass向声明为 in container.h)。

container.cpp将保存.container.h中前向声明类的函数定义以及所有必要的包含container.h。在这个例子中,我只是简单地定义DerivedClasscontainer.cpp不是为它创建另一个头文件并包含它。 在完全定义之后,定义了一个进行虚拟调用Container的函数,并且是.container.cppIsValidDerivedClasscontainer.cpp

main.cpp只需设置所有这些并调用该函数。

如何保持这种使用模式,并构造代码以便dynamic_cast在调用时访问完整类型?

标签: c++rtti

解决方案


推荐阅读