Q:

C++ dynamic objects. How is object size determined during runtime?

I don't understand one thing. For example, I declare class A and class B which is a child of A:
class A {
    public:
        int a;
}

class B : public A {
    public:
        int b;
}

Obviously, if I create instances of A or B, their size in the memory can be determined by the type.
A instanceA; // size of this will probably be the size of int (property a)
B instanceB; // size of this will probably be twice the size of int (properties a and b)

But what if I create dynamic instances and then free them later?
A * instanceAPointer = new A();
A * instanceBPointer = new B();

These are instances of different classes but the program will consider them as instances of class A. That's fine while using them but what about freeing them? To free allocated memory, the program must know the size of memory to free, right?
So if I write
delete instanceAPointer;
delete isntanceBPointer;

How does the program know, how much memory, starting from the address each pointer is pointing to, it should free? Because obviously the objects have different size but the program considers them to be of type A.
Thanks

A:

I am going to assume you know how delete works.
As to how delete knows how to clean up an inherited instance. That's why you use a virtual destructor in inheritance context, otherwise you'll have undefined behavior. Basically, the destructor, like every other virtual function is called via a vtable.
Also recall that: The C++ compiler implicitly destructs the parent class(es) in your destructor
class A {
    public:
        int a;
    virtual ~A(){}
}

class B : public A {
    public:
        int b;
    ~B() { /* The compiler will call ~A() at the very end of this scope */ }
}

That is why this will work;
A* a = new B();
delete a;

By means of vtable, the destructor ~B() will be called by delete. Since the compiler implicitly inserts the destructor call of base class(es) in derived class(es), the destructor of A will be called in ~B().

A:

The behaviour is undefined if you delete an object through a pointer to a base subobject and the class of the subobject does not have a virtual destructor.
On the other hand, if it does have a virtual destructor, then the virtual dispatch mechanism takes care of deallocating the correct amount of memory for the correct address (i.e. that for the complete, most-derived object).
You can discover the address of the most-derived object yourself by applying dynamic_cast<void*> to any appropriate base subobject pointer. (See also this question.)

