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

| 给定以下类结构:
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!”。 是否有任何方法可以强制转换或操纵对象,以使派生版本的outputMessage方法被多态调用? 编辑:我将尝试显示为什么我在此之后的原因: 我正在编写挂接到我们主系统的迁移工具。因此,我需要访问受保护的成员方法或自定义现有的虚拟方法。我可以通过定义一个派生类并向其强制转换对象来静态调用方法来实现。我不能做的是更改我不是静态调用的方法(即在代码库其他地方调用的方法)的行为。 我也尝试过直接创建派生类的对象,但是由于对通过构造函数传递的对象的操作,这会导致系统其他部分出现问题。     
已邀请:
没有符合标准的解决方案 使用C ++标准所保证的行为是不可能的。 如果您确实必须这样做,作为协助迁移的短期措施,不要在生产中依赖它,并且可以充分验证其行为,则可以按照以下说明进行试验。 讨论您的尝试 我正在显示的是您使用了错误的方法:仅将指向基础的指针强制转换为源自对象的指针并不会改变对象的vtable指针。 得出合理的破解 为了解决这个问题,幼稚的方法是将对象适当地重构为派生对象(\“ placement \”
new
),但这也不起作用-它将重新初始化基类成员。 您可能要做的就是创建一个非派生对象,该对象没有数据成员,但具有相同的虚拟调度表条目(即,相同的虚拟功能,相同的可访问性私有/受保护/公共,相同的顺序)。 更多警告和警告 它可能可以工作(就像在我的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”。 实际上,通过向下转换,您正在此处输入未定义行为的土地。这可以像具有多重继承的炸弹一样爆炸,其中派生类中的vtable与基类中的vtable不在同一偏移量。     
好吧,即使在内部将基础对象转换为派生对象,它仍然是基础对象:对象的vftable(函数到RAM指针的实际映射)不会更新。 我不认为有任何方法可以做您想做的事,我也不知道您为什么要这样做。     
在此问题中,c ++ Robs答案中的垂头丧气的问题也应该是您的问题的答案。     
至少不是以合法的方式。要调用Derived类函数,需要引用Derived对象。     

要回复问题请先登录注册