Search code examples
c++methodsvirtualpropagation

What is the reason of implicit virtual-ness propagation?


I've only been working with C++ for 2~3 months and recently I found out about the identifier, final, that comes after a virtual function. To this day, I believed that omission of virtual will stop the propagation of virtualness but I was wrong. It implicitly propagates.

My question is this. Why allow implicit propagation? Why can't an existence of virtual make a function virtual and absense of virtual make a function not virtual? Is is better in some circumstance? or Was it, back in the day when virtual was first introduced?


According to Clifford's answer, there even is a compiler that generates warning upon absense of virtual.


why is the virtuality of methods implicitly propagated in c

I expected above link to answer my question but it doesn't.

------------ Addition -------------

There are comments about asking the usefulness of this feature. I think final keyword on virtual function is what devirtualizes the function. The function can no longer by overridden, so a derived class must re-declare a function whether it has a same name or not. If final is different from devirtualization, Help me to understand it. If final is not different, then usefulness of devirtualization is self-evident from the fact final was introduced. I agree that forcing explicit virtual will produce bugs, but I'm curious if there are other reasons.


Solution

  • The answer as to why a particular feature exists (or doesn't) is usually rather difficult, as it becomes a matter of guessing and opinions. However, the simple answer could be the principle of least astonishment. Coming up with a scheme that makes sense and works reliably and predictably would be difficult.

    What would "devirtualizing" a function even mean? If, at runtime, you're calling a "devirtualized" function on an object, would it use the static type of the pointer instead? If the static type has a virtual function but the runtime type doesn't, what happens?

    #include <iostream>
    
    struct A     {  virtual void f() const { std::cout << "A"; }  };
    struct B : A {          void f() const { std::cout << "B"; }  };
    struct C : B {  virtual void f() const { std::cout << "C"; }  };
    struct D : C {          void f() const { std::cout << "D"; }  };
    
    void f(const A& o) { o.f(); }
    
    int main()
    {
                    // "devirtualized"     real C++
    
        f(A{});     // "A"                 "A"
        f(B{});     // "A" or "B"?         "B"
        f(C{});     // "C"?                "C"
        f(D{});     // oh god              "D"
    }
    

    There's also the fact that for the vast majority of designs, a virtual function has to stay virtual in the whole hierarchy. Requiring virtual on all of them would introduce all sorts of bugs that would be very hard to diagnose. C++ usually tries to stay away from features that require discipline to get right.