What is the reason for removing the ability to stop the propagation of methods virtuality?
Let me be clearer: In C++, whether you write "virtual void foo()" or "void foo()" in the derived class, it will be virtual as long as in the base class, foo is declared virtual.
This means that a call to foo() through a derived* pointer will result in a virtual table lookup (in case a derived2 function overrides foo), even if this behavior is not wanted by the programmer.
Let me give you an example (that looks pretty blatant to me) of how it would be useful to stop virtuality propagation:
template <class T>
class Iterator // Here is an iterator interface useful for defining iterators
{ // when implementation details need to be hidden
public:
virtual T& next() { ... }
...
};
template <class T>
class Vector
{
public:
class VectIterator : public Iterator<T>
{
public:
T& next() { ... }
...
};
...
};
In the example above, the Iterator base class can be used to achieve a form of "type erasure" in a much more clearer and Object-Oriented way. (See http://www.artima.com/cppsource/type_erasure.html for an example of type erasure.)
But still, in my example one can use a Vector::VectIterator object directly (which will be done in most cases) in order to access the real object without using the interface.
If virtuality was not propagated, calls to Vector::VectIterator::next() even from a pointer or reference would not be virtual and would be able to be inlined and to run efficiently, just as if the Iterator interface didn't exist.
I think the reason is that it would be really confusing to remove virtuality partway through an inheritance structure (I have an example of the complexity below).
However if your concern is the micro-optimization of removing a few virtual calls then I wouldn't worry. As long as you inline the virtual child method's code, AND your iterator is passed around by value and not reference, a good optimizing compiler will already be able to see the dynamic type at compile time and inline the whole thing for you in spite of it being a virtual method!
But for completeness, consider the following in a language where you can de-virtualize:
You could make rules for exactly which methods would get called but the obvious choice will vary from person-to-person. It's far simpler to just propagate virtualness of a method.
In my opinion one of the good reasons for this propagation is the
virtual
destructors. In C++ when you have a base class with somevirtual
methods you should define the destructorvirtual
. This is because some code may have a pointer of base class which is actually pointing to the derived class and then tries to delete this pointer (see this question for more detail). By defining the destructor in base class asvritual
you can make sure all pointers of base class pointing to a derived class (in any level of inheritance) will delete properly.C++11 added the contextual keyword
final
for this purpose.The simple snswer is : Don't mix concrete and abstract interfaces! The obvious approach in you example would be the use of a non-
virtual
functionnext()
which delegates to avirtual
function, e.g.,do_next()
. A derived class would overridedo_next()
possibly delegating to a non-virtual
functionnext()
. Since thenext()
functions are likelyinline
there isn't any cost involved in the delegation.