2

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 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.

tvStatic
  • 921
  • 1
  • 9
  • 26
  • 1
    Why do you need this? Actually, when you had to do such a task this tells about design problems. – maverik Apr 14 '11 at 06:02
  • 1
    I will attempt to give an understanding of the why of this in the question. – tvStatic Apr 14 '11 at 06:10
  • possible duplicate of [downcast problem in c++](http://stackoverflow.com/questions/4187747/downcast-problem-in-c) – Bo Persson Apr 14 '11 at 06:29
  • @Bo: I don't think so - the linked question seems to be asking whether simply casting to a derived object allocates additional memory for additional members, and why using them appears to work (answer obviously "luck / undefined behaviour"). This Q is more about virtual functions, which aren't mentioned in the other. – Tony Delroy Apr 14 '11 at 07:17
  • @Tony - Ok, the other question uses Derived's data instead of Derived's functions, but otherwise the code is identical (including class names :-) And the problem is the same - you can't do it! – Bo Persson Apr 14 '11 at 07:34
  • @Bo: well, as per my answer - some bodgy hacks are possible for the vtable that aren't applicable to data. Clearly unsuitable for production, but may be good enough for say running in a dev environment to generate some tentative analysis or documentation of the system's characteristic behaviour... – Tony Delroy Apr 14 '11 at 08:00

5 Answers5

5

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.

Xeo
  • 129,499
  • 52
  • 291
  • 397
2

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'
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
1

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.

Bruce
  • 7,094
  • 1
  • 25
  • 42
1

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

Community
  • 1
  • 1
ChrisWue
  • 18,612
  • 4
  • 58
  • 83
0

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

iammilind
  • 68,093
  • 33
  • 169
  • 336