Skip to content

Last updated:2026-10-12

C++ virtual Functions

About the Author:

Personal WeChat official account:

wechat

1. Virtual Functions and Runtime Polymorphism

Corresponding code: emp.cpp

Which virtual function is called is determined by the type of the object pointed to or referred to, not by the type of the pointer or reference itself.

2. vptr and vtable

See All About vptr_vtable

3. Default Arguments in Virtual Functions

Corresponding code: default_arg.cpp

Default arguments are statically bound, while virtual functions are dynamically bound. The default argument used depends on the type of the pointer or reference itself, not on the type of the object.

4. Allowed or Not

(1) Can a static function be declared virtual?

There are two main reasons:

A static function cannot be declared virtual, nor can it be modified with the const or volatile keywords

A static member function belongs to no class object or class instance, so adding virtual to such a function is meaningless

Virtual functions rely on vptr and vtable. vptr is a pointer, created in the class's constructor and accessible only through the this pointer; static member functions have no this pointer, so they cannot access vptr.

Code to study: static_error.cpp

(2) Can a constructor be virtual?

A constructor cannot be declared virtual. Besides inline and explicit, no other keywords are allowed on constructors.

Why can't a constructor be virtual?

Although the virtual function table vtable is built at compile time, the pointer to the virtual function table, vptr, only comes into existence at runtime when the object is instantiated. If a class contains virtual functions, the compiler adds code in the constructor to create the vptr. Here is the problem: if the constructor were virtual, it would need the vptr to access the vtable — but at that point the vptr does not exist yet. Therefore a constructor cannot be virtual.

The reason we use virtual functions is to run polymorphically with incomplete information. A constructor, on the other hand, initializes an instance, and the instance's type must be definite. Hence there is no need for a constructor to be declared virtual.

Code to study:

(3) Can a destructor be virtual?

A destructor can be declared virtual. If we need to delete a base-class pointer that points to a derived class, the destructor should be declared virtual. In fact, whenever a class might be inherited by other classes, it should declare a virtual destructor (even if the destructor does nothing).

Code to study:

(4) Can a virtual function be private?

  • When a base-class pointer points to a derived-class object, the derived-class object's function is called;
  • int main() must be declared a friend of class Base, otherwise compilation fails. The compiler reports: ptr cannot access the private function. Of course, if the base class is declared public and the derived class private, the problem disappears.

Code to study:

(5) Can a virtual function be inlined?

Normally, the compiler considers whether to inline class member functions. But a virtual function invoked through a base-class pointer or reference can never be inlined. Of course, when a virtual function is called on an actual object, or invoked statically, it can be inlined; a statically invoked virtual destructor will certainly be inlined and expanded.

  • A virtual function can be an inline function — inline may modify a virtual function — but when the virtual function exhibits polymorphism it cannot be inlined.
  • inline is a suggestion to the compiler to inline at compile time, whereas a virtual function's polymorphism happens at runtime; the compiler cannot know which code will be called at runtime, so a virtual function cannot be inlined when it behaves polymorphically (at runtime).
  • The only time inline virtual can be inlined is when the compiler knows which class the called object belongs to (e.g. Base::who()), which happens only when the compiler has an actual object rather than a pointer or reference to the object.

Code to study:

5. RTTI and dynamic_cast

RTTI (Run-Time Type Identification) lets a program use a base-class pointer or reference to check the actual derived class of the object those pointers or references point to.

In object-oriented programming, we sometimes need to query at runtime whether an object can be used as a certain polymorphic type. Similar to Java's instanceof and C#'s as and is operators, C++ provides dynamic_cast for dynamic casting. Compared with C-style casts and C++ reinterpret_cast, dynamic_cast provides a type-safety check — it is a capability-query-based conversion — so dynamic_cast is the preferred way to convert between polymorphic types.

Code to study:

6. Pure Virtual Functions and Abstract Classes

See All About Pure Virtual Functions and Abstract Classes

Comments