I guess why many C programming teams avoid virtual keyword is because this innocent-looking keyword can cause complexity explosion when mixed with other elements —
– dynamic cast for pointer or reference variables
– pure virtual functions
– slicing — without virtual, slicing is more consistent and easier to debug
– passing a RTTI object by reference — note an object is an RTTI object IFF it has a virtual pointer.
– throwing an RTTI exception object by reference, by pointer or by value — again, things are simpler without virtual
– member function hiding (by accident) — without virtual, the hiding rule is simpler
– non-trivial destructors
– pointer delete — for example, deleting a derived object via a base pointer is undefined behavior if the destructor is non-virtual. If you avoid virtual completely, we would less likely write this kind of buggy code.
– double pointers — pointer to pointer to an RTTI object
– double dispatch — usually involves virtual functions. Double-dispatch may not be very meaningful to non-RTTI objects.
– container of RTTI objects, such as vector of pointer-to-base, where each pointee can be a Derived1 object or Derived2 object… — again, non-RTTI cases are simpler
– templates — remember STL internally uses no virtual function, and perhaps very little inheritance
– smart pointers holding RTTI objects
– private inheritance
– multiple and virtual inheritance
Some experts advocate all base classes should have virtual destructor. In that case, avoiding virtual means avoiding inheritance. That would definitely reduce complexity.