ProgrammingBackend Developer (C++)

What are virtual functions and how does the late binding mechanism work in C++?

Pass interviews with Hintsage AI assistant

Answer.

Background of the question:

C++ introduced support for object-oriented programming, which is fundamental for modern languages. To implement polymorphism, virtual functions were used. This allowed the necessary implementation of a method to be called at runtime rather than just at compile time, which is critical for inheritance-based architecture.

Problem:

A common mistake is the confusion between static and dynamic method calls, forgotten virtual destructors, incorrect handling of inheritance (for example, object slicing, calling the base version instead of the override). Often misunderstood is when polymorphism is actually working.

Solution:

A virtual function is declared with the virtual keyword in the base class and can be overridden in the derived class. If a function is called through a pointer or reference to the base class, the version from the derived class will be executed.

Code example:

struct Base { virtual void foo() { std::cout << "Base::foo "; } }; struct Derived : Base { void foo() override { std::cout << "Derived::foo "; } }; void call(Base& b) { b.foo(); } int main() { Derived d; call(d); // Will output Derived::foo }

Key features:

  • Late binding (dynamic dispatch): the method version is chosen at runtime
  • Working through pointers and references to the base class
  • Correct function overriding requires the override keyword (possible since C++11)

Tricky questions.

Does polymorphism work when passing an object by value?

No. Passing by value leads to "slicing" — only the part corresponding to the parameter type (usually the base class) is copied, and polymorphism is disabled.

Code example:

void call(Base b) { b.foo(); } // always calls Base::foo

Is it necessary to declare the destructor virtual in the base class?

Yes, if deletion of derived objects through a pointer to the base class is expected. Otherwise, there will be a memory leak or resources will not be released.

Code example:

struct Base { virtual ~Base() {} };

What happens if the override keyword is not used in the derived class?

If the override is not specified in the derived class, but the function signature is incorrectly changed (for example, missing const or incorrect parameters), the function will not override the virtual one, a new one is created, and polymorphism will not work as expected.

Common mistakes and anti-patterns

  • Not declaring the virtual destructor
  • Incorrectly implemented override (missing override, changing signature)
  • Using value parameters instead of references/pointers, leading to slicing

Real-life example

Negative case

The programmer did not declare the destructor of the base class as virtual; deleting an array of objects through a base pointer led to memory leaks.

Pros:

  • Correct operation until the objects are deleted

Cons:

  • Leaks, resources not released

Positive case

A virtual destructor was declared; only references/pointers to the base type were used. Polymorphism worked correctly.

Pros:

  • Safety of memory release
  • Clean, scalable code

Cons:

  • Minor increase in memory and execution time due to the virtual table