views:

168

answers:

6

Hello StackOverflow

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.

A: 

Assuming you mistyped your last block of code and the names match:

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

Then the C::Foo method is being called or you are using a terribly bad compiler.

(This also assumes that you don't actually have a compiler error in C::Foo, and that the comment is actually something like std::cout << "Hi mom!" << std::endl;)

dash-tom-bang
A: 

Don't you mean:

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

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

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

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

This prints 'C' as expected.

Nikola Smiljanić
Oh shoot yea. Changed the variable name in an edit, not to just call it variable. Must have forgotten the second line. Edited
Trenskow
A: 

I don't follow. You're saying

But only B::bar() is called, not C::Bar()

No. You invoked the constructor of class C, which means that the vtable makes bar() point to C::bar(), so calling foo() in this case would go straight to C::bar().

If you want to force A::foo() to explicitly only call A's implementation, you can do that by just writing

void foo() { A::bar(); }

What exactly are you trying to do?

EboMike
+1  A: 

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;
}
Chris Schmich
A: 

what compiler are you using? Visual Studio (IIRC) usually has the runtime type information turned off by default so maybe its just something simple as that?

Anders K.
+1  A: 
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.

DeadMG
Or you cast B* to A* first and then cast A* to void*.
Tomek