2015-03-30 1 views
0

Например, есть цепьКак выделить память для объекта производного класса указателем базового класса с помощью malloc?

class A 
{ 
int a; 
int b; 
public: 
A(); 
}; 

class B: public A 
{ 
int c; 
char b; 
public: 
B() 
}; 

обычным способом создать объект производного класса, мы можем использовать эту форму

A* ptr = new B() 

Как сделать то же самое с помощью таНос?

+0

В вашем коде B не является производным от A. – BitTickler

+0

Спасибо, теперь исправлено. –

+2

@ ՎարդանԳրիգորյան Почему вы используете 'malloc' вместо' new'? – PaulMcKenzie

ответ

3

C-способ сделать это:

A* ptr = (A*)malloc(sizeof(B)); 
*(B*)ptr = B(); 

C++ - способ сделать это:

A* ptr = static_cast<A*>(malloc(sizeof(B))); 
*static_cast<B*>(ptr) = B(); 

Обратите внимание, что поскольку мы используем C++, мы необходимо указать возвращаемое значение malloc.

В связи с «языковой смесью» для ответа на этот вопрос нет «способа ANSI».

+1

С классами, опубликованными OP, как это можно использовать без вызова неопределенного поведения при попытке использовать то, что было создано? – PaulMcKenzie

+0

@PaulMcKenzie: Вы имеете в виду проблему 'int b' и' char b'? Я воздержался от упоминания об этом, потому что это не было главной задачей вопроса. На самом деле, если вы более подробно рассмотрите это, вы заметите, что этот код даже не будет компилироваться из-за нескольких других ошибок. Но опять же, я предпочел рассмотреть основной вопрос, предполагая, что это были просто опечатки в куске кода, который был написан быстро (и небрежно), чтобы проиллюстрировать эту проблему. –

+1

Это определяемый пользователем конструктор 'B()' и что 'B()' имеет родительский класс. Это делает его не-POD, поэтому использование 'malloc' для создания такого объекта жизнеспособно только при использовании' placement new'. – PaulMcKenzie

4

Malloc возвращает указатель void* на необработанную выделенную память. Просто используйте новый оператор размещения в этой памяти.

void* mem = malloc(sizeof(B)); 
A* ptr = new(mem) B(); // builds object in location pointed by mem 

Место размещения новое не выделяет память, оно просто конструирует ваш объект в данном месте.

+0

Но почему вы берете sizeof (B)? Если вы хотите выделить память для int, тогда вы можете написать так: int * ptr = (int *) malloc (sizeof (int)), это означает, что вы берете тип ptr, который является int (избегая указателя) –

+0

@ ՎարդանԳրիգորյան Если вы хотите, вы можете написать 'B * mem = malloc (sizeof (B));'. В этом случае нет никакой разницы. – lodo

+1

@ ՎարդանԳրիգորյան. Но если вы дадите 'mem' тип' B * ', вы рискуете забыть вызов нового места размещения и попробуйте напрямую использовать этот указатель с плохими результатами ... – lodo

2

new выполняет двухэтапную конструкцию экземпляра класса. Он выделяет кучную память, а затем вызывает конструктор класса для инициализации объекта.

operator new(size_t size) в свою очередь касается только распределения памяти и имеет подпись, аналогичную malloc(). Он не вызывает конструктор для экземпляра.

operator new(size_t size, void* ptr) это место размещения новое. Он возвращает ptr после полной инициализации экземпляра, вызывая соответствующий конструктор.

Если вам нужно использовать другие типы памяти, кроме стандартной кучи, вы можете переопределить новый оператор и место размещения для вашего класса. Это пригодится, если вам нужно поместить экземпляр, скажем, в локальное хранилище потоков, разделяемую память или если вы создадите некоторые оптимизированные структуры данных. Кроме того, размещение new иногда используется в системном программировании, помещая экземпляр объекта поверх некоторого набора регистров с известным адресом, чтобы обеспечить некоторую абстракцию аппаратного интерфейса.

Итак, если вы хотите/должны использовать malloc() для своих экземпляров, все, что вам нужно сделать, это переопределить новый оператор для вашего класса. И, возможно, не забудьте вызвать конструктор.

#include <new> 

A *ManuallyConstructBInstance() 
{ 
    B *pB = reinterpret_cast<B*>(operator new(sizeof(B))); 
    if(nullptr != pB) 
    { 
     new(pB) B(); // manual call of constructor using placement new. 
    } 
    return pB; // optionally use static_cast<A*>() if you want to emphasize the upcast. 
} 

В примере коды выше показано, как это выглядит, как если оператор новый() используются в качестве таНоса() заменителя, демонстрируя, что он имеет дело только с сырой памятью и не имеет incling по типам классов и т.д.

Чтобы узнать, как перегрузить новый оператор для вашего класса, см., Например, here.

+0

Пожалуйста, можете ли вы привести небольшой пример того, как вызвать ctor после выделения памяти, используя указатель базового класса? –

+0

'operator new (size_t size, void * ptr)' не просто возвращает 'ptr'! Он инициализирует ваш объект, его виртуальную таблицу, значения по умолчанию ... – lodo

+0

@lodo right - это «полный конструктор», который необходимо прояснить. – BitTickler

Смежные вопросы