2010-02-18 8 views
2

내가 이러한 구조체를 가지고 말 :메모리 할당과 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에 대한 메모리 할당이 충분하지 않습니다.

+0

그것은 작동하지 않습니다, 문제는 정확히 유 상속 개는 이러한 종류의를 C++에서 – Drakosha

+1

배열을하고 싶어 할 것입니다. 그것이 거의 항상'vector <> '를 사용하는 이유 중 하나입니다. 'Derived * '는'Base *'로 사용할 수 있지만, 배열은 다형성을 갖지 않지만 형성됩니다. –

+1

'memcpy'는'std :: copy'이어야하고'std :: vector'를 사용해야합니다. – GManNickG

답변

0

당신은 템플릿으로 쉽게 할 수 있습니다 :

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; 
} 
+0

괜찮은 것 같습니다. 그러나 이러한 유형의 혼합 유형 모음을 원한다면 작동하지 않습니다. 하지만 OP가 혼합 콜렉션을 수행하지 않고있을 수도 있습니다. –

+0

혼합 된 컬렉션에서는 작동하지 않습니다. OP의 예에 따라 수집 된 항목의 배열을 정의하기가 어려울 것입니다. 포인터에 대한 포인터가 필요합니다. 이 시점에서 올바른 복사를 수행하려면 가상 할당 기능의 일부 형식을 사용해야합니다. – Goz

1

예! 네가 옳아. 그것은 작동하지 않을 것이다. Derived1은 Base보다 크기 때문에 Base에 대한 할당은 메모리가 충분하지 않습니다.

2

포인터를 사용하고 복사 생성자를 사용해야합니다. 아, 또한 기본 데이터 구조 이상에 키워드 struct을 사용하지 마십시오. 기술적으로는 작동하지만 클래스 계층 구조이므로 생성하려는 키워드는 class입니다.

파생 클래스가 크고 목적과 목적이 완전히 다르므로 Base과 인터페이스가 다르지만 더 중요한 것은 클래스를 처리 할 때 실제로 낮은 값을 사용하지 않아야하기 때문입니다 수준의 메모리 조작. 대신 복사 생성자를 설정하고 < 알고리즘과 같은 라이브러리를 사용하여 템플릿 생성 작업을 수행해야합니다.

는 더욱 더, 그것은 법적 구문 (예 : Base * = Derived *를) 임에도 불구하고, 작동하지 않습니다 이유 이유는, 당신은보다 큰 개체를 할당하는 것이 무엇인지 Base * 것 메모리를 작성하여 메모리 손상으로 이어질 것으로 인덱스, 잘못된 위치로

예를 들어, Base 개체가 4 바이트 인 경우 C++은 4 바이트마다 배열을 인덱싱하지만 실제 할당 된 Derived 개체가 8 바이트이면 개체 경계를 중간에 인덱싱하므로 멤버 변수는 메모리의 올바른 위치를 가리키고있다. 배열의

사용하여 클래스 계층 : 심지어 더

Base *objects[100]; 
for (int i = 0; i < 100; i++) 
    objects[i] = new Derived(); 

, 당신은 스마트 포인터 메커니즘 대신 원시 포인터의 템플릿 목록을 사용할 수 있습니다, 관리하는 일을 더 쉽게 만들 수 있습니다.

+0

+1 올바른 OOP 방법은이 작업을 수행하는 것입니다. 또한 원래의'Base * data = new Derived [100];은 합법적 인 구문 일 수 있지만 다형성 관점에서는 의미가 없습니다 (배열은 항상 포인터와 같은 것은 아님). – JonM

+0

@JonM 네 말이 맞아. 예를 들어 본질적으로 컴파일러가 메모리 손상을 초래할 4 바이트 객체로 인덱스 할 때 100 8 바이트 객체를 할당합니다. 두 번째 Base 인덱스는 실제로 첫 번째 인덱스의 두 번째 인덱스가됩니다. –

0

예. Derived의 메모리 사용 공간은 Base의 메모리 사용 공간보다 크기 때문에 복사본이 의도 한대로 작동하지 않습니다.

0

음, an array of Derived is not an array of Base.당신이 Base*Derived*를 업 캐스팅해야하는 경우

, 당신은, 바람직하게는, 자료에 대한 포인터의 배열을 할당하거나해야 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을 사용해야합니다. 그것은이 같은 BaseDerived 수정이 필요합니다 :

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

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