从基 class 指针访问派生 class 成员
Accessing derived class member from base class pointer
我真的很困惑。我 运行 进入以下情况,其中 C 从 A 和 B 继承,但根据事物的分配方式,我得到不同的行为:
如果我 new
一个 C
实例,并将它存储在一个 A
指针中,然后将它的值分配给一个 B
指针,并使用 A
指针调用 A
的方法,并使用 B
指针调用 B
的方法,我得到了奇怪的东西......(见 测试 1).
如果我 new
一个 C
实例,并将其存储在 C
指针中,然后将其值分配给 A
和 B
指针,并使用 A
指针调用 A
的方法,并使用 B
指针调用 B
的方法,我得到了我所期望的。 .(参见 测试 2)。
我的问题是:为什么测试 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
。
我真的很困惑。我 运行 进入以下情况,其中 C 从 A 和 B 继承,但根据事物的分配方式,我得到不同的行为:
如果我
new
一个C
实例,并将它存储在一个A
指针中,然后将它的值分配给一个B
指针,并使用A
指针调用A
的方法,并使用B
指针调用B
的方法,我得到了奇怪的东西......(见 测试 1).如果我
new
一个C
实例,并将其存储在C
指针中,然后将其值分配给A
和B
指针,并使用A
指针调用A
的方法,并使用B
指针调用B
的方法,我得到了我所期望的。 .(参见 测试 2)。
我的问题是:为什么测试 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
。