多态性和数组指针

7

我有一个A类:

class A
{
    public:
        virtual double getValue() = 0;
}

还有一个B类:

class B : public A
{
    public:
        virtual double getValue() { return 0.0; }
}

然后在main()函数中我执行:

A * var;
var = new B[100];
std::cout << var[0].getValue(); //This works fine
std::cout << var[1].getValue(); //This, or any other index besides 0, causes the program to quit

如果我改为:

B * var;
var = new B[100];
std::cout << var[0].getValue(); //This works fine
std::cout << var[1].getValue(); //Everything else works fine too

所有的编译都很顺利,但似乎我的多态有些问题?我感到困惑。

3个回答

12
你不能使用多态来处理数组,因此,虽然new B[100]创建了一个B对象的数组并返回指向数组的指针,或等效于数组的第一个元素的指针,并且将该指针分配给基类指针是有效的,但是这不允许将其视为指向A对象数组的指针。
主要原因是(通常)派生对象与其基类的大小不同,因此尝试将数组作为基类对象数组访问将不使用正确的偏移量获取指向下一个派生类数组成员的下一个基类子对象的指针。

@Charles 我假设如果他将数组更改为 A ** var,那么这个限制就不适用了(并通过 new 初始化所有100个项目)。 - Glen
@Glen:不太确定你的意思。你会有一个指针数组而不是对象数组。因为指针不从其他指针派生,所以问题不会出现。 - CB Bailey
@Stewart:你最终想要实现什么?如果你有一个指向动态创建对象的指针数组,那么你就会面临很多内存管理问题。为什么不保留一组B对象并只保留正确的类型呢? - CB Bailey
1
@Glen:嗯,是的,它可以工作,但现在他必须手动分配100个对象,并且在某个时候进行解除分配。就我个人而言,我会选择对象数组(或更可能使用std::vector<B>)。 - CB Bailey
@Charles,当然,但如果他想把B、C、D和E对象放入数组中,那么他就必须使用指针。(而且我看到他最新的评论说这是他想要的) - Glen
显示剩余8条评论

6

多态没有问题,但是你处理内存的方式有问题。在第一种情况下,[]运算符将以sizeof(A)字节的大小向数组中前进,而在第二种情况下,则是以sizeof(B)字节的大小向前移动。由于对象是B类型,因此A*指向的位置不正确。

这是另一种看待它的方式

char * var;
var = (char*) new B[100];
std::cout << ((A*)var[0]).getValue(); //This works fine
std::cout << ((A*)var[1]).getValue(); //This will fail
std::cout << ((A*)var[sizeof(B)]).getValue(); // should work

-1

你没有为数组分配对象:

for (int i=0;i<100;i++)
  var[i] = new B;

(虽然我可能混淆了C++和C#)

不要认为那是正确的。这是一个B对象的数组,而不是指向B对象的指针数组。 - Glen
var 是一个指针变量,而不是指向指针的指针,因此 var[i] = new B 不是有效的(除非有一个不寻常的赋值运算符接受一个指针)。 - CB Bailey
1
不,你说得对。大多数面向对象的编程语言(我使用过的)在创建对象数组方面都是以相同的方式工作的。 - user106596
2
那需要将 var 定义为指针数组。B ** var; - Alan
不,他正在分配对象数组,而不是对象指针数组。 - RamblingMad
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接