C++ new[] 在数组访问时进入基类指针崩溃

2022-01-24 00:00:00 inheritance arrays polymorphism c++

当我分配一个对象时,这段代码可以正常工作.当我尝试添加数组语法时,它会出现段错误.为什么是这样?我的目标是向外界隐藏 c 类在内部使用 b 对象的事实.我已将程序发布到 codepad 供您使用.

When I allocate a single object, this code works fine. When I try to add array syntax, it segfaults. Why is this? My goal here is to hide from the outside world the fact that class c is using b objects internally. I have posted the program to codepad for you to play with.

#include <iostream>

using namespace std;

// file 1

class a
{
    public:
        virtual void m() { }
        virtual ~a() { }
};

// file 2

class b : public a
{
    int x;

    public:
        void m() { cout << "b!
"; }
};

// file 3

class c : public a
{
    a *s;

    public:
        // PROBLEMATIC SECTION
        c() { s = new b[10]; } // s = new b;
        void m() { for(int i = 0; i < 10; i++) s[i].m(); } // s->m();
        ~c() { delete[] s; } // delete s;
        // END PROBLEMATIC SECTION
};

// file 4

int main(void)
{
    c o;

    o.m();

    return 0;
}

推荐答案

一个问题是表达式 s[i] 使用指针算法来计算所需对象的地址.由于 s 被定义为指向 a 的指针,因此结果对于 as 数组是正确的,而对于 b 数组则不正确s.继承提供的动态绑定只对方法有效,其他无效(例如,没有虚拟数据成员,没有虚拟 sizeof).因此,当调用方法 s[i].m() 时,this 指针被设置为 ith a 数组中的对象.但是由于实际上该数组是 b 之一,它最终(有时)指向对象中间的某个位置,并且您会遇到段错误(可能是当程序尝试访问对象的 vtable 时)).您也许可以通过虚拟化和重载 operator[]() 来解决问题.(不过,我没有仔细考虑它是否真的有效.)

One problem is that the expression s[i] uses pointer arithmetic to compute the address of the desired object. Since s is defined as pointer to a, the result is correct for an array of as and incorrect for an array of bs. The dynamic binding provided by inheritance only works for methods, nothing else (e.g., no virtual data members, no virtual sizeof). Thus when calling the method s[i].m() the this pointer gets set to what would be the ith a object in the array. But since in actuality the array is one of bs, it ends up (sometimes) pointing to somewhere in the middle of an object and you get a segfault (probably when the program tries to access the object's vtable). You might be able to rectify the problem by virtualizing and overloading operator[](). (I Didn't think it through to see if it will actually work, though.)

另一个问题是析构函数中的delete,原因类似.您也可以虚拟化和重载它.(再说一次,我脑子里突然冒出一个随机的想法.可能行不通.)

Another problem is the delete in the destructor, for similar reasons. You might be able to virtualize and overload it too. (Again, just a random idea that popped into my head. Might not work.)

当然,投射(根据其他人的建议)也可以.

Of course, casting (as suggested by others) will work too.

相关文章