A a = *(A *)new B();
a.func();
Вот что происходит в этом коде, шаг за шагом:
new B()
: новый объект типа B выделяется в свободном хранилище, в результате чего его адрес (A*)
: адрес объекта приведен к A*
, поэтому у нас есть указатель типа A*
, фактически указывающий на объект типа B, который является допустимым.Все в порядке. A a
: здесь начинаются проблемы.Новый локальный объект типа A создается в стеке и создается с использованием конструктора копирования A::A(const A&)
, причем первым параметром является объект, созданный ранее. - Указатель на исходный объекттипа B теряется после этого оператора, что приводит к утечке памяти, так как он был выделен в свободном хранилище с
new
. a.func()
- метод вызывается для (локального) объекта классаA.
Если вы измените код на:
A& a = *( A*) new B();
a.func();
, то будет создан только один объект, его указатель будет преобразован в указатель типа A*
, а затем разыменовани новая ссылка будет инициализирована с этим адресом .Вызов виртуальной функции будет затем динамически разрешен до B::func()
.
Но помните, что вам все равно нужно освободить объект, так как он был выделен с помощью new
:
delete &a;
Что, кстати, будет правильным только в том случае, если у A есть виртуальный деструктор, для которого требуется B :: ~ B () (который, к счастью, здесь пуст, но вобщий случай) так же будет называться.Если у А нет виртуального деструктора, вам нужно освободить его:
delete (B*)&a;
Если вы хотите использовать указатель, то это то же самое, что и со ссылкой.Код:
A* a = new B(); // actually you don't need an explicit cast here.
a->func();
delete (B*)a; // or just delete a; if A has a virtual destructor.