Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling virtual function in subclass from superclass

I know this question must have been covered endless of times, but I've searched the previous questions, and nothing seems to pop.

It's about inheritance and virtual functions i C++. I have a problem with calling virtual functions in subclasses from the superclass.

Let me give an example. Start of with three classes, which inherit from each other.

class A {

    void foo() { bar() }
    virtual void bar() { }

};

class B : public A {

    virtual void bar() { }

};

class C : public B {

    virtual void bar() { // do something }

};

Now I wanna have a variable declared as B* but instantiated as C*.

B* myObject = new C();
myObject->foo();

When I do this, and call foo() on myObject, then A::foo() is calling bar(). But only B::bar() is called, not C::Bar() - which in reality myObject is, even though it's declared as B, which again affects that "// do nothing" doesn't get executed.

How do I tell A::foo(), that it needs to look at lowest implementation?

Makes sense?

// Trenskow

EDIT:

C::Foo is not the problem. Foo is being called in class A, as it's the only place it's implemented. The problem arises, when A:Foo calls Bar(). Then B:Bar is called and not C::Bar.

Maybe the problem is, that in my implementation, I only get a void* pointer to the object in A.

Like this:

void A:Foo(void *a) {

    A* tmpA = static_cast<A*> (a);
    tmpA->bar();

}

Now the compiler thinks, that tmpA is an A. But somehow it manages to figure that it's a B*, and calls B::Bar, when in fact tmpA is a C* and it should be calling C::Bar.

like image 907
Trenskow Avatar asked Aug 22 '10 09:08

Trenskow


2 Answers

The following prints "A::foo C::bar" as expected. Are you getting something different? B::bar is never called because C is the actual runtime type of the object. In C::bar, you could call B::bar explicitly by adding B::bar(); to its body.

#include <iostream>
using namespace std;

class A {
public:
    void foo() { cout << "A::foo "; bar(); }
    virtual void bar() { }
};

class B : public A {
public:
    virtual void bar() { cout << "B::bar" << endl; }
};

class C : public B {
public:
    virtual void bar() { cout << "C::bar" << endl; }
};

int main()
{
    B* c = new C();
    c->foo();
    return 0;
}
like image 189
Chris Schmich Avatar answered Sep 20 '22 02:09

Chris Schmich


void A:Foo(void *a) {

    A* tmpA = static_cast<A*> (a);
    tmpA->bar();

}

This is undefined behaviour. You cannot cast a B* to a void*, then cast that void* back to an A*. If you want it to work properly, you have to ditch the void*. Alternatively, you could try dynamic_cast.

like image 31
Puppy Avatar answered Sep 22 '22 02:09

Puppy