从基类下载时,是否可以调用派生对象的虚方法?

时间:2011-04-14 05:59:56

标签: c++ inheritance polymorphism

给出以下类结构:

class Base
{
    virtual void outputMessage() { cout << "Base message!"; }
};

class Derived : public Base
{
    virtual void outputMessage() { cout << "Derived message!"; }
}

..和此代码段:

Base baseObj;
Derived* convertedObj = (Derived*) &baseObj;
convertedObj->outputMessage();

..输出将是“Base message!”。

有没有办法转换或操作对象以使Derived的outputMessage方法版本被多态调用?

修改:我会尝试说明我之后的原因:

我正在编写挂钩到我们主系统的迁移工具。出于这个原因,我需要访问受保护的成员方法,或自定义现有的虚拟方法。前者我可以通过定义派生类并将对象强制转换为静态来调用方法。我不能做的是改变我不静态调用的方法的行为(即在代码库中的其他地方调用的方法)。

我还尝试直接创建派生类的对象,但由于操作通过构造函数传递的对象,这会导致系统其他部分出现问题。

5 个答案:

答案 0 :(得分:5)

不,虚函数对指向的对象的实际类型进行操作,在您的情况下只是一个简单的Base。 实际上,通过降级,你在这里进入未定义行为的土地。这可以像一个具有多重继承的炸弹一样被吹掉,其中派生类中的vtable与基类中的vtable的偏移量不同。

答案 1 :(得分:1)

好吧,即使您将Base对象作为派生对象进行内部渲染,它仍然是一个Base对象:对象的vftable(RAM指针的实际函数映射)不会更新。 我认为没有办法做你想做的事情,我不明白你为什么要这样做。

答案 2 :(得分:1)

在这个问题中downcast problem in c++ Robs的回答也应该是你问题的答案。

答案 3 :(得分:1)

没有符合标准的解决方案

您尝试做什么无法使用C ++标准保证的行为

如果您真的必须将此作为短期措施来帮助您迁移,不要在生产中依赖它,并且可以充分验证行为,您可以实验,如下图所示。

讨论您的尝试

我所展示的是你采取了错误的方法:简单地将指针指向某个指向派生的指针不会改变对象的vtable指针。< / p>

得出似乎合理的黑客

解决这个问题,天真的方法是将对象重建为派生对象(“placement”new),但不起作用 - 它将重新初始化基类成员。

可能做的是创建一个非派生对象,该对象没有数据成员但相同的虚拟调度表条目(即相同的虚函数,相同的辅助功能私有) / protected / public,同样的命令)。

更多警告和警告

可能工作(就像在我的Linux机器上一样),但使用它需要您自担风险(我建议在生产系统上)。

进一步警告:这只能拦截虚拟调度,当编译器在编译时知道类型时,有时可以静态调度虚函数。

~/dev cat hack_vtable.cc
// change vtable of existing object to intercept virtual dispatch...

#include <iostream>

struct B
{
    virtual void f() { std::cout << "B::f()\n"; }

    std::string s_;
};

struct D : B
{
    virtual void f() { std::cout << "D::f()\n"; }
};

struct E
{
    virtual void f() { std::cout << "E::f()\n"; }
};

int main()
{
    B* p = new B();
    p->s_ = "hello";
    new (p) D();  // WARNING: reconstructs B members

    p->f();
    std::cout << '\'' << p->s_ << "'\n"; // no longer "hello"

    p->s_ = "world";
    new (p) E();
    p->f();  // correctly calls E::f()
    std::cout << '\'' << p->s_ << "'\n"; // still "world"
}

~/dev try hack_vtable   
make: `hack_vtable' is up to date.
D::f()
''
E::f()
'world'

答案 4 :(得分:0)

至少不合法。要调用Derived类函数,您需要引用Derived对象。