我创建了一个名为 vir 的类,其中包含 move 函数:

class vir
{
public:
     vir(int a,int b,char s){x=a;y=b;sym=s;}
     void move(){}
};

(它来自带有变量的类int x,int y和sym),我从此派生了一个类,称为subvir:

class subvir:public vir
{
public:
     subvir(int a,int b,char s){x=a;y=b;sym=s;}
     void move();
};
subvir::move()
{
     x++;
     return;
}

然后我创建了一个 vir 数组,并将一个 subvir 放入其中

subvir sv1(0,0,'Q');
vir vir_RA[1]={sv1};

但是当我尝试使用 sv1.move() 时:

vir_RA[0].move();

它使用 vir move ({}) 而不是 subvir move ({x++})。我尝试过将 sv1 设为 vir,将 vir_RA 设为 vir,它可以工作,当我将它们都设为 subvir 时,它也可以工作,但我需要它们不同。我尝试将 vir::move() 设为纯虚拟,但随后在证实数组时出现错误。有谁知道当我从数组中使用 move() 时如何让 move() 工作?

有帮助吗?

解决方案

在这种情况下,您需要一个指针数组,而不是一个实例数组。使用vir * []代替vir []

其他提示

您遇到了一个名为切片的问题。使用指针数组,或类似 Boost.ptr_container

基类必须有 virtual 函数来获得你想要的东西,使它们成为纯函数将产生一个抽象基类——你无法实例化的东西。但是,您仍然可以创建指向抽象基类的指针/引用,并将派生类对象分配给它们。您的基类最好表示为:

class vir
{
public:
     vir(int a,int b,char s){x=a;y=b;sym=s;}
     virtual void move(){}
};

这使得派生类的 move 虚拟的也是如此。然而你的 move 定义缺少返回值并且无法编译。尝试:

void subvir::move()
{
     x++;
     return;
}

请注意,您需要指针(如其他答案中所述)或对派生类的引用才能使动态绑定发挥作用。所以,而不是数组 vir 对象,使用基类指针数组:

vir* v[ 2 ] = { new subvir(0, 0, 'Q'), new subvir(10, -10, 'P') };

您还应该对C ++常见问题解答的以下各节进行阅读:

两件事。数组是vir的数组,所以当然它使用了vir :: move。 move()不是虚方法。

但更重要的是切片。您不能将子类放入数组中。如果sizeof vir!= sizeof subvir,则阵列将无法正确排列。目前它们的大小相同。但如果他们不这样做会发生什么。

是的,基本上编译器不允许在数组中使用子类,因为 对于类型大小,数组被紧密初始化,并且子类型倾向于 要比父母大,如果可以的话会导致问题 使用子类型值初始化数组。 真正发生的是编译器首先分配数组N * size(base_type)字节。 然后它复制每个初始化的大小(base_type)字节 对象。如果他们是不同的类型,他们会被截断, 你的代码可能会发生奇怪的事情。

让我巩固以前的答案。

这里实际上有两个问题。一个是切片。您正在使用子文件的副本初始化一组virs。在这种情况下,编译器将vir部分从子文件中切出并将其复制到数组中,因此您确实只在那里获得了vir对象。现在在你的特殊情况下,subvir没有超出vir的额外数据成员,所以切片有点退化,vir对象看起来很像subvir。然而,vir和subvir是不同的类,并且数组中的对象最终是vir对象而不是伪装成vir的subvir对象。实际上,即使两者具有相同的数据成员,两者之间的差异实际上也会表现出来的一种方式是,如果vir具有由子记录重载的虚函数。在这种情况下,数组中对象中的vtable指针将指向vir的vtable,而不是subvir。当然,如果subvir包含在vir中找不到的其他数据成员,那将更加明确。

第二个问题是多态性。在使用时(对move()的调用),编译器认为你正在调用类型为vir的对象的move()方法(因为数组是virs的数组)。 (编译器当然是正确的,因为切片,在这种情况下可能会退化。)如果它实际上是你想要的subvir对象,你可以通过移动来调用subvir :: move()(虚拟的虚拟。

要获得所需的行为,您可以使用指针数组(但之后您将直接在sv1上运行,而不是它的副本,除非您首先创建副本并使用指向副本的指针初始化数组)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top