我真的很困惑。我遇到了以下情况,其中C继承了A和B,但是根据事物的分配方式,我得到了不同的行为:
如果我new
C
实例,并将其存储在A
指针中,则将其值分配给B
指针,然后调用方法使用A
指针的A
和使用B
指针的B
方法,我得到了奇怪的东西......(参见测试1 )。
如果我new
C
个实例,并将其存储在C
指针中,请将其值分配给A
和B
指针,并使用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;
}
答案 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
。