C++ 从基类指针访问派生类成员

C++ 从基类指针访问派生类成员,c++,pointers,variable-assignment,multiple-inheritance,derived-class,C++,Pointers,Variable Assignment,Multiple Inheritance,Derived Class,我真的很困惑。我遇到了以下情况,其中C同时从A和B继承,但根据分配的方式,我得到了不同的行为: 如果我newaC实例,并将其存储在a指针中,然后将其值分配给aB指针,并使用a指针调用a方法,使用B指针调用B方法,我会得到一些奇怪的东西。。。(请参见测试1) 如果我newaC实例,并将其存储在C指针中,然后将其值分配给a和B指针,并使用a指针调用a的方法,以及使用B指针调用B的方法,我将得到我所期望的。。。(参见测试2) 我的问题是:为什么测试1的行为如此 A类 class A { publi

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

  • 如果我
    new
    a
    C
    实例,并将其存储在
    a
    指针中,然后将其值分配给a
    B
    指针,并使用
    a
    指针调用
    a
    方法,使用
    B
    指针调用
    B
    方法,我会得到一些奇怪的东西。。。(请参见测试1)

  • 如果我
    new
    a
    C
    实例,并将其存储在
    C
    指针中,然后将其值分配给
    a
    B
    指针,并使用
    a
    指针调用
    a
    的方法,以及使用
    B
    指针调用
    B
    的方法,我将得到我所期望的。。。(参见测试2)

我的问题是:为什么测试1的行为如此

A类

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

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

class C : public A, public B
{
public:
    C() : A(), B() {}
    virtual ~C() {}
};
包含Test1和Test2的Main

#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*C;
A*A;
B*B;
printf(“测试1\n”);
a=新的C();
b=(b*)a;
printf(“a->getAMember():%c\n”,a->getAMember());//打印
printf(“b->getBMember():%c\n”,b->getBMember());//打印A?!
printf(“测试2\n”);
c=新的c();
a=c;
b=c;
printf(“a->getAMember():%c\n”,a->getAMember());//打印
printf(“b->getBMember():%c\n”,b->getBMember());//打印b
返回0;
}

您使用的是一个邪恶的C型演员阵容,在本例中相当于
重新解释演员阵容
。这将
A
子对象的地址重新解释为
B
子对象的地址,该子对象实际上位于另一个地址;强制转换无效,如果您试图通过该指针访问a
B
,则会给出未定义的行为

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


在第二种情况下,您可以安全地从派生类转换为基类,因此一切都定义得很好,不需要任何强制转换导致未定义的行为。像这样的铸造是强制a型的。您应该使用动态_cast

a = new C();
b = dynamic_cast<B*>(a);
a=newc();
b=动态_型铸造(a);

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