static_cast如何影响虚函数调用?

时间:2013-06-26 18:19:13

标签: c++

我有以下代码(从virtual functions and static_cast被盗):

#include <iostream>

class Base
{
public:
   virtual void foo() { std::cout << "Base::foo() \n"; }
};

class Derived : public Base
{
public:
   virtual void foo() { std::cout << "Derived::foo() \n"; }
};

如果我有:

int main()
{
   Base base;
   Derived& _1 = static_cast<Derived&>(base);
   _1.foo();
}

打印输出为:Base::foo()

但是,如果我有:

int main()
{
   Base * base;
   Derived* _1 = static_cast<Derived*>(base);
   _1->foo();
}

打印输出为:Segmentation fault: 11

老实说,我对两者都不太了解。有人可以根据上面的例子解释static_cast和虚方法之间的复杂性吗?顺便说一句,如果我希望打印输出为“Derived::foo()”,我该怎么办?

4 个答案:

答案 0 :(得分:5)

在你的第二个例子中,你是段错误,因为你没有实例化你的基指针。所以没有v-table可以调用。尝试:

Base * base = new Base();
Derived* _1 = static_cast<Derived*>(base);
_1->foo();

这将打印Base :: foo()

这个问题毫无意义,因为static_cast不会影响v-table。但是,这对非虚函数更有意义:

class Base
{
public:
   void foo() { std::cout << "Base::foo() \n"; }
};

class Derived : public Base
{
public:
    void foo() { std::cout << "Derived::foo() \n"; }
};


int main()
{
   Base base;
   Derived& _1 = static_cast<Derived&>(base);
   _1.foo();
}

这个将输出Derived :: foo()。然而,这是非常错误的代码,虽然它编译,但行为未定义

答案 1 :(得分:5)

指针或引用类型的有效static_cast根本不会影响虚拟调用。根据对象的动态类型解析虚拟调用。指针或引用的static_cast不会改变实际对象的动态类型。

您在示例中观察到的输出无关紧要。这些例子很简单。

第一个无效static_cast。在底层对象不是Base &的情况下,您不能将Derived &强制转换为Derived。任何执行此类转换的尝试都会产生不确定的行为。

以下是static_cast对参考类型向下转型的有效应用示例

int main()
{
   Derived derived;
   Base &base = derived;
   Derived& _1 = static_cast<Derived&>(base);
   _1.foo();
}

在您的第二个示例中,代码完全被破坏,原因与任何强制转换或虚拟调用无关。代码试图操纵非初始化的指针 - 行为未定义。

答案 2 :(得分:2)

虚函数的整个目的是变量的静态类型无关紧要。编译器将查找对象本身的实际实现(通常使用隐藏在对象中的vtable指针)。 static_cast应该没有效果。

答案 3 :(得分:2)

在这两个示例中,行为都是未定义的。 Base对象不是Derived对象,并告诉编译器假装它不是一个对象。获取代码打印"Derived::foo()"的方法是使用Derived类型的对象。