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

时间:2015-03-31 14:38:16

标签: c++ pointers variable-assignment multiple-inheritance derived-class

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

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

  • 如果我new C个实例,并将其存储在C指针中,请将其值分配给AB指针,并使用A指针调用A方法,使用B指针调用B方法,我得到了我期望的...(参见< strong>测试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&amp; 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;
}

2 个答案:

答案 0 :(得分:3)

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

使用dynamic_cast安全地在同一个完整对象的多态基类子对象之间进行交叉转换(如果要转换指针,请记住检查结果);或者static_cast到派生类(在这种情况下,到C*),如果你完全确定你指向那种类型的对象。

在第二种情况下,您可以安全地从派生类转换为基类,因此一切都定义良好,无需任何转换。

答案 1 :(得分:1)

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

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

这将允许运行时由于您的虚函数而实际检查a的类型,并生成正确的结果。如果演员阵容不是合适的演员阵容,则会导致nullptr