2

我真的很困惑。我跑进了以下情况,其中C从A和B都继承,但根据事情是如何分配的,我得到不同的行为:从基类指针访问派生类成员

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

  • 如果我new一个C实例,并将其存储在一个C指针,然后分配给它的价值的AB指针,并调用使用A指针的A的方法,以及BB的方法指针,我得到我期望的...(见测试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

#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; 
} 
+0

指针转换的危险之处在于编译器会让你做到,即使它没有意义。 – 2015-03-31 14:46:57

+0

你也可以考虑阅读以下文章:http://stackoverflow.com/questions/9374244/casting-pointer-to-base-class-into-a-pointer-to-derived-class – 2015-03-31 14:52:06

回答

3

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

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

在第二种情况下,您可以安全地将派生类转换为基类,因此所有内容都可以很好地定义,无需任何投射。

1

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

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

这将允许运行时间实际检查由于您的虚拟功能,以及产生正确的结果的类型。如果演员阵容不合适,将导致nullptr

相关问题