Explain how C++ decides which function to call for base_ptr->draw() when draw is virtual. What goes wrong if a polymorphic base class has a non-virtual destructor?
Show the explanation
Static vs dynamic binding. For a non-virtual function, the compiler picks the function from the static type of the pointer (Base*), at compile time. For a virtual function, the choice happens at run time from the dynamic type: the actual class of the object the pointer refers to.
How compilers usually implement it. The standard does not require this layout, but every mainstream compiler uses it:
- Each class with virtual functions has a vtable, a table of function pointers with one slot per virtual function. Each slot points to that class's override.
- Each object of such a class carries a hidden vptr that points to its class's vtable. The constructor sets it.
p->draw()compiles to roughly: load the vptr, load thedrawslot, call it. That is one or two extra memory loads per call, and the call usually cannot be inlined.
Virtual destructor
struct Base { ~Base() {} }; // not virtual
struct Derived : Base { std::vector<int> big; };
Base *p = new Derived;
delete p; // undefined behaviourDeleting a derived object through a base pointer whose destructor is not virtual is undefined behaviour. In practice Derived's destructor does not run, so big leaks. Rule: if a class is meant to be used polymorphically (it has any virtual function), give it a public virtual destructor, for example virtual ~Base() = default;. If you never want deletion through a base pointer, make the destructor protected and non-virtual instead.
Related points
- Calling a virtual function from a constructor or destructor does not dispatch to the derived class. During base construction the object is still only a
Base. overrideandfinallet the compiler check your intent.- A pure virtual function (
= 0) makes the class abstract. - Polymorphism needs references or pointers. Passing by value slices the object down to the base part.
Original UniCircle question. Last reviewed 22 Oct 2026.
