C++ C+中的内存分配和继承类+;

C++ C+中的内存分配和继承类+;,c++,inheritance,dynamic-memory-allocation,C++,Inheritance,Dynamic Memory Allocation,假设我有这些结构: struct Base{ ... } struct Derived:public Base{ //everything Base contains and some more } 我有一个函数,我想复制一个数组,然后修改它 void doStuff(Base *data, unsigned int numItems){ Base *newdata = new Base[numItems]; memcpy(newdata, data, numItems*sizeof

假设我有这些结构:

struct Base{
 ...
}

struct Derived:public Base{
 //everything Base contains and some more
}
我有一个函数,我想复制一个数组,然后修改它

void doStuff(Base *data, unsigned int numItems){
 Base *newdata = new Base[numItems];
 memcpy(newdata, data, numItems*sizeof(Base));
 ...
 delete [] newdata;
}
但是如果我这样使用这个函数:

Base *data = new Derived[100];
doStuff(data, 100);

这不管用,是吗?因为Derived1大于Base,所以为Base分配的内存不足?

是!你说得对。这是行不通的。因为Derived1大于Base,所以为Base分配的内存不足。

正是如此。这是的一个变体。

您可以使用模板轻松完成此操作:

template< class T >void doStuff(T *data, unsigned int numItems)
{
    T *newdata = new T[numItems];
    memcpy( newdata, data, sizeof( T ) * numItems );
    ...
    delete [] newdata;
}
templatevoid doStuff(T*数据,无符号整数)
{
T*newdata=newt[numItems];
memcpy(新数据、数据、大小(T)*numItems);
...
删除[]新数据;
}
根据评论编辑:如果你想为混合收藏做这件事,事情会很快变得更复杂。。。一种可能的解决办法是:

struct Base{
    virtual Base* CopyTo()      { return new Base( *this ); }
};

struct Derived:public Base{
    virtual Derived* CopyTo()   { return new Derived( *this ); }

};

void doStuff( Base** ppArray, int numItems )
{
    Base** ppNewArray   = new Base*[numItems];
    int count = 0;
    while( count < numItems )
    {
        ppNewArray[count] = ppArray[count]->CopyTo();
        count++;
    }

    // do stuff

    count = 0;
    while( count < numItems )
    {
        delete ppNewArray[count];
        count++;
    }
    delete[] ppNewArray;
}
struct Base{
虚拟基*CopyTo(){返回新基(*this);}
};
结构派生:公共基{
虚拟派生*CopyTo(){返回新派生(*this);}
};
空隙度凝灰岩(基底**面积,整数)
{
基本**ppNewArray=newbase*[numItems];
整数计数=0;
while(计数CopyTo();
计数++;
}
//做事
计数=0;
while(计数
您需要使用指针和复制构造函数。哦,还有,除了基本数据结构之外,不要使用关键字
struct
。从技术上讲,它是有效的,但是您要创建的是类层次结构,所以请使用
class
关键字

这不会简单地起作用,因为派生对象更大,而且出于意图和目的,它是一个完全不同的对象,主要通过接口与
Base
兼容,但更重要的是,在处理类时,不应该真正使用低级内存操作。相反,您应该设置复制构造函数,并使用之类的库对其执行模板化操作

此外,尽管是合法语法(即
Base*=Derived*
),但它不起作用的原因是您分配的对象比
Base*
索引的对象大,这将导致内存损坏,将内存写入错误的位置

例如,如果<代码> BASE> /COD>对象是4字节,C++将每四字节索引数组,但是如果实际分配的<代码>派生< /COD>对象是8字节,那么索引在对象边界的中途,并且成员变量不会指向内存中的正确位置。 在数组中使用类层次结构:

Base *objects[100];
for (int i = 0; i < 100; i++)
    objects[i] = new Derived();
Base*对象[100];
对于(int i=0;i<100;i++)
objects[i]=新派生的();

更进一步为了使事情更易于管理,您可能希望使用智能指针机制和模板列表,而不是原始指针。

是的。派生的内存占用空间大于基本的内存占用空间,因此副本将无法正常工作。

好的

如果需要将
派生*
向上转换为
基*
,则应将指针数组分配给基,或者最好是
向量

请注意,要复制对象而不知道它们是
Base
还是
派生的
,我们需要使用。它需要修改
Base
Derived
,如下所示:

struct Base{
    ...
    virtual Base* clone() const { return new Base(*this); }
    virtual ~Base() {}
};

struct Derived : public Base {
    ...
    Derived* clone() const { return new Derived(*this); }
};

它将不起作用,问题是,你希望C++中的数组到底有什么样的继承。这就是我几乎总是使用向量的原因之一。虽然
派生的*
可以用作
基*
,但数组并不是多态的,无论其形式如何。
memcpy
应该是
std::copy
,并使用
std::vector
。这似乎是可以的,但如果您想要这些东西的混合类型的集合,则不起作用。但是也许OP没有做混合收藏?不,它不能用混合收藏。您很难按照OP的示例定义一个集合项数组。你需要指针对指针。在这一点上,您需要使用某种形式的虚拟赋值函数来执行正确的复制。同样重要的是要记住,原始
Base*data=new-Derived[100]
可能是合法的语法,但从多态性的角度看没有意义(数组并不总是和指针一样)。@JonM你说得对。例如,当编译器将100个8字节对象作为4字节对象进行索引时,实际上是分配了100个8字节对象,这将导致内存损坏。第二个基本指数实际上是第一个指数的后半部分。
void doStuff(const vector<Base*>& data)
{
    // Copy the objects, not the pointers
    vector<Base*> newdata;
    for (vector<Base*>::const_iterator it = data.begin();
         it != data.end(); ++it)
    {
        newdata.push_back((*it)->clone());
    }

    // Do stuff

    // Destroy the copies
    for (vector<Base*>::iterator it = newdata.begin();
         it != newdata.end(); ++it)
    {
        delete *it;
    }
}
struct Base{
    ...
    virtual Base* clone() const { return new Base(*this); }
    virtual ~Base() {}
};

struct Derived : public Base {
    ...
    Derived* clone() const { return new Derived(*this); }
};