对于复杂的标题感到抱歉。我有这样的事情:
class Base
{
public:
int SomeMember;
Base() : SomeMember(42) {}
virtual int Get() { return SomeMember; }
};
class ChildA : public Base
{
public:
virtual int Get() { return SomeMember*2; }
};
class ChildB : public Base
{
public:
virtual int Get() { return SomeMember/2; }
};
class ChildC : public Base
{
public:
virtual int Get() { return SomeMember+2; }
};
Base ar[] = { ChildA(), ChildB(), ChildC() };
for (int i=0; i<sizeof(ar)/sizeof(Base); i++)
{
Base* ptr = &ar[i];
printf("El %i: %i\n", i, ptr->Get());
}
哪个输出:
El 0: 42
El 1: 42
El 2: 42
这是正确的行为(在VC ++ 2005中)吗?说实话,我希望这段代码不要编译,但确实如此,但是它没有给我我需要的结果。这有可能吗?
答案 0 :(得分:8)
是的,这是正确的行为。原因是
Base ar[] = { ChildA(), ChildB(), ChildC() };
通过将三个不同类的对象复制到class Base
的对象上并生成class Base
的对象来初始化数组元素,因此您可以从数组的每个元素中观察class Base
的行为。 / p>
如果要存储不同类的对象,则必须使用new
分配它们并存储指针。
答案 1 :(得分:2)
为了实现您期望的多态行为,您应该使用指向Base
的指针数组并通过new
创建对象:
Base* ar[] = { new ChildA(), new ChildB(), new ChildC() };
答案 2 :(得分:0)
实际发生的是:
由于ar []的类型是Base,因此将3 * sizeof(Base)内存量分配给ar。
由于您尚未为Base声明显式复制构造函数,因此调用base的默认复制构造函数,它只是将ChildA,ChildB和ChildC对象的“Base”部分按位复制到数组中包含的Base对象中ar(默认的复制构造函数足够智能,不会将Child对象的虚拟指针按位复制到Base虚拟指针中)。
ar [0],ar [1]和ar [2]的虚拟指针指向Base :: Get,因此调用Base :: Get。
此处需要注意的是,在执行之前,对象的虚拟指针所指向的函数始终是已知的。
在这种情况下,运行时事先知道arr由“Base”对象组成,所以它设置了它们的vptr,以便在它们被分配内存时指向Base :: Get。