关于static_cast的问题

时间:2012-09-02 21:11:42

标签: c++ static-cast

我写了一段代码,但我对它的输出感到困惑:

#include <iostream>

using namespace std;

class B{
public:
    virtual void foo() {cout << "B::foo" << endl;}
};

class D:public B{
public:
    virtual void foo() {cout << "D::foo" << endl;}
    void disp() {cout << "D::disp" << endl;}
};

void func(B *pb){
    D *pd1 = static_cast<D*>(pb);
    pd1->foo();
    pd1->disp();
}

int main(int argc, char *argv[])
{

    B* pb = new B();
    func(pb); 

    return 0;
}

输出结果为:

B::foo
D::disp

但据我所知,pb指向类型B.并且其中没有名为disp()的函数?那么,为什么它可以访问D类中的disp()函数?

5 个答案:

答案 0 :(得分:4)

由于disp()不访问该类的任何成员,因此它原则上与在全局命名空间而不是在类中声明它相同,因此对调用没有负面影响它,即使实例不是正确的类。

你在做什么是将基类的指针向下转换为派生类的指针,即使它没有被初始化。如果disp()尝试访问位于D但不在B中的类成员,则可能会遇到段错误。

底线:除非您完全确定指针实际指向派生类的实例,否则不要使用static_cast进行向下转换。如果您不确定,可以使用dynamic_cast,如果不匹配则会失败(但是有RTTI的开销,所以如果可以,请避免使用它。)

如果演员表不正确,

dynamic_cast将返回nullptr或投出std::bad_cast 如果它转换引用的异常,那么您将确定它失败的原因而不是可能的内存损坏错误。

答案 1 :(得分:2)

该行:

D *pd1 = static_cast<D*>(pb);

无论源指针是B*还是D*,都会进行转换。在您的情况下,结果将是指向错误类型的对象的指针。方法disp将起作用,因为它没有使用类D的任何数据成员或虚函数。在更复杂的情况下,这将导致不稳定的行为或崩溃。

你的物体是polimorphic。您应该使用dynamic_cast代替。

答案 2 :(得分:1)

我认为,在这种情况下,重要的是成员函数disp()不会隐藏在D类型的所有对象中。它是一个存在于一个地方的单一功能。是否有任何对象尝试呼叫disp()是由代码决定的。

您的static_cast将生成编译器认为指向D 的指针,而不管您传递的指针。一旦你有一个指向D的指针,编译器就会让你试着调用disp()

换句话说,static_cast无法保护您不会错误地投射指针。

答案 3 :(得分:1)

当您将指向分配为B的对象的指针强制转换为指向派生类D的指针时,您做了一件非常糟糕的事情。这是标准所说的,强调我的:

  

5.2.9静态演员

     

如果类型“指向cv1 B的指针”的rvalue指向实际上是D类型对象的子对象的B,则生成的指针指向类型D的封闭对象。否则,演员表的结果未定义

您通过执行static_cast调用了未定义的行为。编译器和运行时可以执行任何操作,并且在程序调用未定义的行为时仍然符合要求。

答案 4 :(得分:0)

您需要了解the difference between the various types of C++ casts

你在这里使用静态演员,这与说“我真的不在乎它是否真的属于那种类型 - 只是尽力而为”。

在这种情况下,您想知道您的指针是否实际上是您要将其转换为的派生类型。你应该使用dynamic_cast。仅当指针的类型正确时,此强制转换才会成功。这意味着,如果失败,它将返回一个NULL指针。

你所看到的行为是当你没有为工作使用正确的演员时会发生什么,虽然你可以尝试解释它,但是你真的应该避免它,因为它属于未定义的行为领域。换句话说,您不能指望编译器甚至同一编译器的不同版本具有相同的副作用。换句话说,避免它。