2013-06-26 88 views
1

我有以下代码(来自virtual functions and static_cast被盗):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(); 
} 

打印输出将b e:Segmentation fault: 11

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

+8

如果您对未初始化的指针进行调用,分段错误实际上是最好的结果。 –

+0

要打印输出为Derived :: foo(),您需要确保Derived类型的实例存在,但在任何示例中都不存在。 – mungflesh

+0

由于您没有任何实际的对象,因此您使用指针进行segfault。只是指针,还没有指向任何。所以'_1-> foo()'试图从一个随机内存位置读取虚拟表。如果您将指针更改为'Base base;派生* _1 = static_cast (&base);'然后你可以尝试调用'foo()',但你仍然应该得到'Base :: foo()',因为那是对象。你需要一个'Derived _2; _2.foo()'。 – John

回答

4

在你的第二个例子中,你segfault因为你没有instanciate你的基指针。所以没有v-table可以调用。尝试:

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

这将打印基地:: foo的()

的问题是没有意义的,因为的static_cast不会影响v表。但是,这使得非虚函数更敏感:

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()。然而,这是一个非常错误的代码,虽然它编译,行为是undefined

+1

这个例子仍然被破坏。当源引用不是指向一个[sub]对象时,将'Base&'强制转换为'Derived& 'Derived'类型,在你的例子中行为是不确定的 – AnT

+0

它可能是非法的,是的,我猜它是未定义的,所以也许它在答案中没有它的位置,但是可以问自己为什么这样做会编译并给出这个尽管如此,我会编辑答案,thx。 – lip

2

虚拟函数的全部目的是变量的静态类型应该不重要。编译器将查找对象本身的实际实现(通常在对象内隐藏一个vtable指针)。 static_cast应该没有影响。

4

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

虽然您在示例中观察到的输出不相关。这些例子很简单。

第一个使无效static_cast。在底层对象不是Derived的情况下,您不得将Base &转换为Derived &。任何尝试执行此类转换都会导致未定义的行为。

下面是引用类型的static_cast有效的应用程序的向下转换

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

在第二个例子中的代码是完全打破了什么都没有做任何类型转换或虚拟调用原因的例子。该代码试图操纵未初始化的指针 - 行为是未定义的。

2

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