Search code examples
c++c++11constructorvirtual-functionsdynamictype

Is it bad practice to call a virtual function from constructor of a class that is marked final


Normally calling virtual functions from constructors is considered bad practice, because overridden functions in sub-objects will not be called as the objects have not been constructed yet.

But, Consider the following classes:

class base
{
public:
   base() {}
   ~base() {}

private:
   virtual void startFSM() = 0;
};

class derived final : public base
                    , public fsm_action_interface
{
public:
    derived() : base{}
              , theFSM_{}
    {  startFSM(); }


    /// FSM interface actions

private:
   virtual void startFSM()
   { theFSM_.start(); }

private:
    SomeFSMType theFSM_;
}

In this case class derived is marked as final so no o further sub-objects can exist. Ergo the virtual call will resolve correctly (to the most derived type).

Is it still considered bad practice?


Solution

  • Regarding

    Normally calling virtual functions from constructors is considered bad practice, because overridden functions in sub-objects will not be called as the objects have not been constructed yet.

    That is not the case. Among competent C++ programmers it’s normally not regarded as bad practice to call virtual functions (except pure virtual ones) from constructors, because C++ is designed to handle that well. In contrast to languages like Java and C#, where it might result in a call to a method on an as yet uninitialized derived class sub-object.

    Note that the dynamic adjustment of dynamic type has a runtime cost.

    In a language oriented towards ultimate efficiency, with "you don't pay for what you don't use" as a main guiding principle, that means that it's an important and very much intentional feature, not an arbitrary choice. It's there for one purpose only. Namely to support those calls.


    Regarding

    In this case class derived is marked as final so no o further sub-objects can exist. Ergo the virtual call will resolve correctly (to the most derived type).

    The C++ standard guarantees that at the time of construction execution for a class T, the dynamic type is T.

    Thus there was no problem about resolving to incorrect type, in the first place.


    Regarding

    Is it still considered bad practice?

    It is indeed bad practice to declare a member function virtual in a final class, because that’s meaningless. The “still” is not very meaningful either.

    Sorry, I didn't see that the virtual member function was inherited as such.

    Best practice for marking a member function as an override or implementation of pure virtual, is to use the keyword override, not to mark it as virtual.

    Thus:

    void startFSM() override
    { theFSM_.start(); }
    

    This ensures a compilation error if it is not an override/implementation.