简体   繁体   中英

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:

  • If I new a C instance, and store it in an A pointer, then assign it's value to a B pointer, and call a method of A using the A pointer, and a method of B with the B pointer, I get weird things... (see Test 1 ).

  • If I new a C instance, and store it in an C pointer, then assign it's value to an A and B pointer, and call a method of A using the A pointer, and a method of B with the B pointer, I get what I expect... (see Test 2 ).

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;
}

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.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM