Eric
Eric

Reputation: 17536

Accessing derived class member from base class pointer

I am really confused. I ran into the following situation, where C inherits from both A and B, but depending on how things are assigned, I get different behavior:

My question is: Why does test 1 behave the way it does?

Class A

class A
{
public:
    A() { aMember = 'A'; }
    virtual ~A() {}
    virtual char getAMember() { return aMember; }
private:
    char aMember;
};

Class B

class B
{
public:
    B() { bMember = 'B'; }
    virtual ~B() {}
    virtual char getBMember() { return bMember; }
private:
    char bMember;
};

Class C

class C : public A, public B
{
public:
    C() : A(), B() {}
    virtual ~C() {}
};

Main that has Test1 & Test2

#include <cstdio>

int main(void)
{
    C* c;
    A* a;
    B* b;

    printf("Test 1\n");

    a = new C();
    b = (B*)a;

    printf("a->getAMember(): %c\n",a->getAMember()); // prints A
    printf("b->getBMember(): %c\n",b->getBMember()); // prints A ?!

    printf("Test 2\n");

    c = new C();
    a = c;
    b = c;

    printf("a->getAMember(): %c\n",a->getAMember()); // prints A
    printf("b->getBMember(): %c\n",b->getBMember()); // prints B

    return 0;
}

Upvotes: 2

Views: 687

Answers (2)

Mike Seymour
Mike Seymour

Reputation: 254461

You're using an evil C-style cast, which in this case is equivalent to reinterpret_cast. This reinterprets the address of the A sub-object as that of the B sub-object, which is actually at another address; the cast is invalid, giving undefined behaviour if you try to access a B through that pointer.

Use dynamic_cast to safely cross-cast between polymorphic base class sub-objects of the same complete object (remembering to check the result, if you're casting a pointer); or static_cast to the derived class (in this case, to C*), if you're absolutely sure that you're pointing to an object of that type.

In the second case, you're safely converting from the derived class to the base classes, so everything is well defined with no need for any casting.

Upvotes: 3

Captain Giraffe
Captain Giraffe

Reputation: 14705

It's because this cast b = (B*)a; causes undefined behavior. Casting like this is forcing the type of a. You should use dynamic_cast.

a = new C();
b = dynamic_cast<B*>(a);

This will allow the runtime to actually check the type of a, due to your virtual functions, as well as produce the correct result. If the cast is not a proper cast it will result in a being nullptr.

Upvotes: 1

Related Questions