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); }
};