【问题标题】:using dynamic_cast with templates将 dynamic_cast 与模板一起使用
【发布时间】:2014-05-06 08:35:52
【问题描述】:

在用 C++ 实现基于模板的工厂时,我创建了以下 allocator 函数来实例化给定的子类:

template<class ChildClass, class ParentClass>
ParentClass* allocator() {
   ChildClass *child  = new ChildClass();
   ParentClass*parent = dynamic_cast<ParentClass*>(child);
   if(NULL==parent) {
     delete child;
     return NULL;
   }
   return parent;
}

一切正常,但是当通过coverity 等静态代码分析工具运行代码时,delete child; 行被标记为逻辑死代码

我进行运行时检查的原因是断言ChildClass 是从ParentClass 派生的。

现在我明白了,在模板扩展期间编译器已经知道ChildClass 是否派生自ParentClass,并且dynamic_cast 仅在运行时进行评估。

如果ChildClass 确实是从ParentClass 派生的,那么运行时检查逻辑上是死代码(在这种情况下,如果ChildClass 已成功分配,dynamic_cast 将始终返回non-NULL) .

但是有没有办法确保在编译时(模板扩展时)ChildClass 派生自 ParentClass

afaik,模板和继承在 C++ 中是不相关的,但我可能遗漏了一些明显的东西。

限制

不幸的是,代码应该在较旧的编译器上编译(例如,Visual Studio 6 附带的 C++ 实现)排除了任何较新的扩展,例如 C++11-features

【问题讨论】:

  • 如果你的编译器和库支持 C++11,你可以使用std::is_base_of
  • @JoachimPileborg 好点,但是我希望能够使用 VisualStudio-6 (原文如此!)对我的代码进行旧版编译,所以它甚至不是 @987654340 @
  • 你应该在你的问题中清楚地说明这些限制。
  • @juanchopanza 感谢您的提示,更新了问题
  • 如果无法分配内存,您当前的实现将在new 上抛出std::bad_alloc,而不是nullptr。如果你想在失败时获得nullptr,你应该使用new(std::nothrow) ChildClass(); ;)

标签: c++ templates inheritance dynamic-cast


【解决方案1】:

你可以使用std::is_base_of:

constexpr bool is_base = std::is_base_of<ParentClass, ChildClass>::value;

ChildClass 不是从ParentClass 派生时,您可以在static_assert 中使用它来表示编译器错误。

static_assert(std::is_base_of<ParentClass, ChildClass>::value,
              "ParentClass is not base of ChildClass");

如果你没有 C++11 支持,你可以使用boost::is_base_ofBOOST_STATIC_ASSERT

【讨论】:

    【解决方案2】:

    如果“Derived”继承自“Base”,则可以将“Derived”指针分配给指向“Base”的指针。即:

    void AssignToBase(Derived* derived) {
      Base* base = derived;
    } 
    

    ...以上编译成功证明“Derived”继承自“Base”。您可以将它与 SFINAE 和静态断言(无论是在 C++11 中还是使用 Boost 的静态断言机制)结合使用,以验证派生类是否继承自父类。正如 juanchopanza 所说,C++11 提供了一个简单的 std::is_base_of 类型特征类,您可以使用它来测试这种继承关系。

    【讨论】:

    • 关于返回值,OP 正在返回parent,这将是一个有效的指针或NULL,所以没有错误。
    • @umläute,你是对的。话虽如此,如果这里有一个早期的“return nullptr”,肯定会更容易阅读。
    猜你喜欢
    • 2019-02-01
    • 2016-06-02
    • 1970-01-01
    • 2021-08-08
    • 2014-09-08
    • 1970-01-01
    • 2012-09-15
    • 2011-06-03
    • 2017-09-02
    相关资源
    最近更新 更多