从基 class 指针访问派生 class 成员

Accessing derived class member from base class pointer

我真的很困惑。我 运行 进入以下情况,其中 C 从 A 和 B 继承,但根据事物的分配方式,我得到不同的行为:

我的问题是:为什么测试 1 会这样?

Class一个

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

ClassB

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() {}
};

主要有 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;
}

您正在使用邪恶的 C 风格转换,在本例中相当于 reinterpret_cast。这将 A 子对象的地址重新解释为 B 子对象的地址,实际上在另一个地址;转换无效,如果您尝试通过该指针访问 B,则会出现未定义的行为。

使用dynamic_cast在同一个完整对象的多态基础class子对象之间安全地交叉转换(如果您正在转换指针,请记住检查结果);或 static_cast 到派生的 class(在本例中,到 C*),如果您绝对确定您指向的是该类型的对象。

在第二种情况下,您可以安全地从派生 class 转换为基本 classes,因此一切都已明确定义,无需任何转换。

这是因为此转换 b = (B*)a; 导致未定义的行为。像这样的转换强制 a 的类型。你应该使用 dynamic_cast。

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

这将允许运行时根据您的虚函数实际检查 a 的类型,并产生正确的结果。如果转换不是正确的转换,它将导致 nullptr