开发者

Is it possible to call derived object's virtual method when down-casted from base class?

开发者 https://www.devze.com 2023-02-25 16:07 出处:网络
Given the following class structure: class Base { virtual void outputMessage() { cout << \"Base message!\"; }

Given the following class structure:

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

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

.. and this code snippet:

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

.. the output will be "Base message!".

Is there any way to cast or manipulate the object to make Derived's version of the outputMessage method to be called polymorphically?

Edit: I will attempt to show the reason why I'm after this:

I am writing migration tools that hook into our main system. For this reason, I need to get开发者_StackOverflow社区 access to protected member methods, or customise existing virtual methods. The former I can do by defining a derived class and casting objects to it, to call methods statically. What I can't do is change the behaviour for methods which I do not call statically (ie methods that are called elsewhere in the codebase).

I have also tried creating objects of the derived class directly, but this causes issues in other parts of the system due to the manipulation of the objects passed through the constructor.


No, virtual functions operate on the actual types of the object being pointed to, which in your case is just a simple Base.
Actually, with the down-casting, you're entering undefined-behaviour land here. This can blow off like a bomb with multiple inheritance, where the vtable in the derived class isn't at the same offset as the vtable in the base class.


No Standard-compliant solution

What you're trying to do isn't possible using behaviours guaranteed by the C++ Standard.

If you really MUST do this as a short-term measure to assist your migration, don't depend on it in production, and can adequately verify the behaviour, you could experiment as illustrated below.

Discussion of your attempt

What I'm showing is that you're taking the wrong approach: simply casting a pointer-to-base to a pointer-to-derived doesn't alter the object's vtable pointer.

Deriving a plausible hack

Addressing that, the naive approach is to reconstruct the object in place as a derived object ("placement" new), but this doesn't work either - it will reinitialise the base class members.

What you can possibly do is create a non-derived object that has no data members but the same virtual dispatch table entries (i.e. same virtual functions, same accessibility private/protected/public, same order).

More warnings and caveats

It may work (as it does on my Linux box), but use it at your own risk (I suggest not on production systems).

Further warning: this can only intercept virtual dispatch, and virtual functions can sometimes be dispatched statically when the compiler knows the types at compile time.

~/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'


Well, even if you're casting your Base object as a Derived one, internally, it's still a Base object: the vftable of your object (the actual map of functions to RAM pointers) is not updated. I don't think there is any way to do what you want to do and I don't understand why you'd like to do it.


In this question downcast problem in c++ Robs answer should also be the answer to your problem.


Not at least in legal way. To call Derived class function, you need to have Derived object being referred.

0

精彩评论

暂无评论...
验证码 换一张
取 消