铸造的奇怪产品

时间:2014-12-24 01:01:21

标签: c++ templates virtual-functions

当我像下面这样投射时,我会得到一些奇怪的东西。我的意图是得到这样的东西:

Inside Base
Inside Derived1

但是我获得了无数的“Inside Base”......这是代码:

#include <iostream>
using namespace std;

template<typename Derived>
class Base
{
public:
    virtual void somefunc()
    {
        cout << "Inside Base\n";
        static_cast<Derived*>(this)->somefunc();
    }
};

class Derived1: public Base<Derived1>
{
public:
    void somefunc()
    {
        cout << "Inside Derived1\n";
    }
};

int main(int argc, char** argv)
{
    Base<Derived1> b1;
    b1.somefunc();
    return 0;
}

2 个答案:

答案 0 :(得分:1)

穆罕默德·阿里·贝敦(Mohammad Ali Baydoun)在关于当你演出时没有更新vtable的声明中是正确的。

当您在b1.somefunc()中致电main时,由于b1Base<Derived1>Base<Derived1>::somefunc()将被调用。当您执行强制转换为Derived1时,vtable不会更新,而您投射的对象仍然在内部Base<Derived1>而不是Derived1。 vtable查找导致另一次调用Base<Derived1>::somefunc()而不是Derived1::somefunc(),结果是无限递归。

然而,这是未定义的行为,因为您将基类对象转换为其不是的东西。将Derived1作为模板参数放置并不会使其定义为行为。

答案 1 :(得分:1)

您的代码有未定义的行为。这是一个简短的片段,原理相同:

struct Base { };
struct Derived: Base { int x; };

int main()
{
    Base b;
    static_cast<Derived &>(b).x = 5;
}

即使x不存在,它仍未定义,但我添加它以帮助说明问题。您正在处理对象b,但是内存中的行踪是5被写入了吗?

规则是,如果您使用static_cast从基类到派生类,则必须检查您正在投射的内容实际指向/引用该派生类的实例。如果它是,那么它的工作原理;如果不是那么它是无声的未定义行为。