内存分配和用C继承类++
说我有这些结构:内存分配和用C继承类++
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分配内存不足?
你可以用一个模板做到这一点很容易:
template< class T >void doStuff(T *data, unsigned int numItems)
{
T *newdata = new T[numItems];
memcpy(newdata, data, sizeof(T) * numItems);
...
delete [] newdata;
}
编辑按意见:如果你想做到这一点对于混合收集事情会变得更加复杂,快速...一个可能的解决方案是这样的:
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;
}
这似乎是好的,但如果你想要这些东西的混合类型的集合不会工作。但是,也许OP没有做混合收藏? – 2010-02-18 22:23:21
不,它不适用于混合收藏。根据OP的例子,你很难推动定义一个收集到的项目数组。你需要指针指针。此时,您需要使用某种形式的虚拟分配功能来执行正确的复制。 – Goz 2010-02-18 22:25:51
是的!你是对的。它不会工作。由于Derived1大于Base,因此为Base分配内存不足。
您将需要使用指针并使用复制构造函数。哦,而且,不要使用关键字struct
以上的基本数据结构。从技术上讲,它可以工作,但是你创建的是类层次结构,所以使用class
关键字。
这不会工作,因为衍生更大,意图和目的是一个完全不同的对象,主要通过接口与Base
兼容,但更重要的是,在处理类时,不应该使用低级存储器操作。相反,您应该设置复制构造函数并使用像<算法>的库来对它们执行模板化操作。
更进一步,为什么它不会工作,尽管是合法的语法(即Base * = Derived *
)的原因,是你比分配较大的物体有什么Base *
将索引到,这将通过写入内存导致内存破坏到错误的位置。例如,如果一个Base
对象是4个字节,C++将每四个字节索引数组,但如果实际分配的对象是8个字节,那么您将在对象边界中间索引一半,并且您的成员变量不会指向内存中的正确位置。在一个阵列
使用类层次结构:
Base *objects[100];
for (int i = 0; i < 100; i++)
objects[i] = new Derived();
甚至进一步,使事情更容易管理,你可能想使用智能指针机制和模板列表,而不是原始指针。
+1为正确的OOP方式来做到这一点。记住最初的'Base * data = new Derived [100];'也许是合法的语法,但是从多态的角度来看没有意义(数组并不总是与指针相同的东西)也是很重要的。 – JonM 2010-02-18 22:39:50
@JonM你是对的。例如,当编译器将它们编入索引为4字节的对象时,它本质上会分配100个8字节的对象,这会导致内存损坏。第二个基地指数实际上是第一个的下半部分。 – 2010-02-18 22:46:08
是的。 Derived的内存占用量大于Base的内存占用量,因此副本无法按预期工作。
那么,an array of Derived is not an array of Base。
如果需要上溯造型一Derived*
到Base*
,你应该分配的指针数组基地,或最好,一个vector<Base*>
vector<Base*> data(100);
// Initialize the elements
for (vector<Base*>::iterator it = data.begin(); it != data.end(); ++it)
{
*it = new Derived;
}
doStuff(data);
// Destroy the elements
for (vector<Base*>::iterator it = data.begin(); it != data.end(); ++it)
{
delete *it;
}
而且你doStuff
函数变为:
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;
}
}
请注意,要复制对象而不知道它们是Base
还是Derived
,我们需要使用virtual constructor idiom。它需要修改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 – Drakosha 2010-02-18 22:18:56
阵列++有这些类型与继承陷阱的。这是我几乎总是使用'vector '的一个原因。虽然'Derived *'可以用作'Base *',但是数组不是多态的,但是形成了。 – 2010-02-18 22:39:08
'memcpy'应该是'std :: copy',并使用'std :: vector'。 – GManNickG 2010-02-18 22:43:43