8

我有一个普通的旧 CRPT(请不要被访问限制分心 - 问题不在于它们):

 template<class Derived>
 class Base {
     void MethodToOverride()
     {
        // generic stuff here
     }
     void ProblematicMethod()
     {
         static_cast<Derived*>(this)->MethodToOverride();
     } 
 };

像往常一样打算这样使用:

 class ConcreteDerived : public Base<ConcreteDerived> {
     void MethodToOverride()
     {
        //custom stuff here, then maybe
        Base::MethodToOverride();
     }
 };

现在这static_cast让我很困扰。我需要一个向下转换(不是向上转换),所以我必须使用显式转换。在所有合理的情况下,转换都是有效的,因为当前对象确实属于派生类。

但是,如果我以某种方式改变了层次结构并且演员现在变得无效怎么办?

在这种情况下,我可以以某种方式强制执行显式向下转换是否有效的编译时检查吗?

4

5 回答 5

5

在编译时,您只能检查静态类型,这就是static_cast已经做的。

给定 a Base*,它只是并且只能在运行时知道它的动态类型是什么,也就是说,它是否实际上指向 aConcreteDerived或其他东西。所以如果你想检查这个,它必须在运行时完成(例如通过使用dynamic_cast

于 2011-05-06T06:47:04.147 回答
4

为了更加安全,您可以向 Base 添加一个受保护的构造函数,以确保从它派生一些东西。那么唯一的问题将是真正愚蠢的人:

class ConcreteDerived : public Base<SomeOtherClass>

但这应该在第一次代码审查或测试用例中发现。

于 2011-05-06T07:07:58.530 回答
3

要扩展@Bo Persson 所说的内容,您可以使用例如 Boost.TypeTraits 或 C++0x/11 在所述构造函数中进行编译时检查<type_traits>

#include <type_traits>

template<class Derived>
struct Base{
  typedef Base<Derived> MyType;

  Base(){
    typedef char ERROR_You_screwed_up[ std::is_base_of<MyType,Derived>::value ? 1 : -1 ];
  }
};

class ConcreteDerived : public Base<int>{
};

int main(){
  ConcreteDerived cd;
}

Ideone 上的完整示例。

于 2011-05-06T07:27:45.590 回答
2

似乎有一种方法可以在编译时检查 CRPT 的正确性。

通过使 Base 抽象(向 Base 添加一些纯虚拟方法),我们保证任何 Base 实例都是某个派生实例的一部分。

通过将所有 Base 构造函数设为私有,我们可以防止来自 Base 的不良继承。

通过将 Derived 声明为 Base 的朋友,我们允许 CRPT 期望的唯一继承。

在此之后,CRPT 向下转换应该是正确的(因为某些东西是从基类继承的,而这个“东西”可能只是派生的,而不是其他一些类)

也许出于实际目的,第一步(使 Base 抽象)是多余的,因为成功的 static_cast 保证 Derived 位于 Base 层次结构中的某个位置。如果 Derived 继承自Base <Derived> (如 CRPT 所期望的)但同时 DerivedBase <derived> 在 Derived 代码的某处创建另一个实例(没有继承)(它可以,因为它是朋友),则这仅允许出现异常错误。但是,我怀疑有人会不小心写出如此奇特的代码。

于 2012-06-28T10:22:25.803 回答
1

当您执行以下操作时:

struct ConcreteDerived : public Base<Other>  // Other was not inteded

您可以创建对象class(派生或基础)。但是如果你尝试调用该函数,它static_cast只会给出与相关的编译错误。恕我直言,它将满足所有实际情况。

如果我正确理解了这个问题,那么我觉得答案就在你的问题本身中。:)

于 2011-05-06T07:54:30.760 回答