在C++中使用'static_cast'进行向下转换

G M*_*ann 14 c++

考虑:

class base
{
    base();
    virtual void func();
}

class derived : public base
{
    derived();
    void func();
    void func_d();
    int a;
}


main
{
    base *b = new base();
    sizeof(*b); // Gives 4.
    derived * d = static_cast<derived*>(b);
    sizeof(*d); // Gives 8- means whole derived obj size..why?
    d->func_d();
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我做了一个基指针的向下转换,它指向基对象到派生类指针.我想知道派生指针如何具有整个派生类对象.我可以调用派生类函数(仅在派生类中声明).我没有在这里得到这个概念.

Ben*_*igt 21

使用static_cast投对象的类型,它实际上并不具有收益不确定的行为.UB的症状差异很大.没有什么可以说UB不能允许成功调用派生成员函数(但是没有任何东西可以保证它会被调用,所以不要指望它).

下面是使用的规则static_cast,可以在[expr.static.cast]C++标准的5.2.9()部分找到(C++ 0x措辞):

类型为"指向cv1的 指针"的prvalue B,其中B是一个类类型,可以转换为类型为"指向cv2的 指针"的prvalue D,其中D是一个派生自的类B,如果是从"指针D"到"指针"的有效标准转换到B"的存在,CV2是相同的CV-资格,或更大的CV-资格比,CV1,并且B 既不是虚基类的D,也不是基类的虚拟基类的D.空指针值将转换为目标类型的空指针值.如果"指向cv1的 指针B" 类型的prvalue指向B实际上是类型对象的子对象D,则生成的指针指向类型的封闭对象D.否则,演员的结果是不确定的.


Mar*_*ork 9

进行运行时检查的唯一转换是dynamic_cast<>().如果演员阵容在运行时无法运行,则应使用此演员表.

因此从叶子 - >根(向上铸造)铸造static_cast<>()工作正常.
但是从root-> leaf(向下转换)进行转换是危险的,并且(在我看来)应该总是这样做,dynamic_cast<>()因为对运行时信息有依赖性.成本很低,但总是值得为安全付出代价.

  • 应该注意,只有基类定义虚函数时,`dynamic_cast`比`static_cast`更安全. (3认同)
  • @Ben:如果您向下转换,如果类型不是多态的(即具有虚函数),则会出现编译时错误。如果您正在向上转换,那么它是安全的,因为它无论如何都相当于 static_cast。 (2认同)
  • @Ben:这意味着您无法在其中获得编译时错误。这也暗示(但不能确认)您的类应该首先是多态的。我认为编译时错误没有危害。与运行时UB相比,它是无限可取的。如果您向下转换,则可能是您的设计有问题(或者需要指出(而dynamic_cast使它突出显示))。无论哪种方式,dynamic_cast都会使设计更安全;容易发现的编译时错误或运行时检查。 (2认同)

Pup*_*ppy 6

sizeof存在于编译时.它既不知道也不关心在运行时,你的基础对象不指向a derived.您试图用运行时变量影响编译时行为,这从根本上是不可能的.

  • @AttitudeMonger 你的问题是什么?一个类的所有实例共享相同的大小。`sizeof` 计算为编译时常量,而不是运行时“度量”。成员函数在类实例中不占用空间。虚拟指针可能,这就是基于`sizeof` 的调整的用武之地——这同样不会阻止你调用 UB。 (2认同)