Calling virtual functions inside constructors

前端 未结 13 1065

Suppose I have two C++ classes:

class A
{
public:
  A() { fn(); }

  virtual void fn() { _n = 1; }
  int getn() { return _n; }

protected:
  int _n;
};

clas         


        
相关标签:
13条回答
  • 2020-11-21 06:04

    The C++ Standard (ISO/IEC 14882-2014) say's:

    Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class. If the virtual function call uses an explicit class member access (5.2.5) and the object expression refers to the complete object of x or one of that object’s base class subobjects but not x or one of its base class subobjects, the behavior is undefined.

    So, Don't invoke virtual functions from constructors or destructors that attempts to call into the object under construction or destruction, Because the order of construction starts from base to derived and the order of destructors starts from derived to base class.

    So, attempting to call a derived class function from a base class under construction is dangerous.Similarly, an object is destroyed in reverse order from construction, so attempting to call a function in a more derived class from a destructor may access resources that have already been released.

    0 讨论(0)
  • 2020-11-21 06:06

    During the object's constructor call the virtual function pointer table is not completely built. Doing this will usually not give you the behavior you expect. Calling a virtual function in this situation may work but is not guaranteed and should be avoided to be portable and follow the C++ standard.

    0 讨论(0)
  • 2020-11-21 06:08

    As has been pointed out, the objects are created base-down upon construction. When the base object is being constructed, the derived object does not exist yet, so a virtual function override cannot work.

    However, this can be solved with polymorphic getters that use static polymorphism instead of virtual functions if your getters return constants, or otherwise can be expressed in a static member function, This example uses CRTP (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).

    template<typename DerivedClass>
    class Base
    {
    public:
        inline Base() :
        foo(DerivedClass::getFoo())
        {}
    
        inline int fooSq() {
            return foo * foo;
        }
    
        const int foo;
    };
    
    class A : public Base<A>
    {
    public:
        inline static int getFoo() { return 1; }
    };
    
    class B : public Base<B>
    {
    public:
        inline static int getFoo() { return 2; }
    };
    
    class C : public Base<C>
    {
    public:
        inline static int getFoo() { return 3; }
    };
    
    int main()
    {
        A a;
        B b;
        C c;
    
        std::cout << a.fooSq() << ", " << b.fooSq() << ", " << c.fooSq() << std::endl;
    
        return 0;
    }
    

    With the use of static polymorphism, the base class knows which class' getter to call as the information is provided at compile-time.

    0 讨论(0)
  • 2020-11-21 06:09

    Do you know the crash error from Windows explorer?! "Pure virtual function call ..."
    Same problem ...

    class AbstractClass 
    {
    public:
        AbstractClass( ){
            //if you call pureVitualFunction I will crash...
        }
        virtual void pureVitualFunction() = 0;
    };
    

    Because there is no implemetation for the function pureVitualFunction() and the function is called in the constructor the program will crash.

    0 讨论(0)
  • 2020-11-21 06:11

    The C++ FAQ Lite Covers this pretty well:

    Essentially, during the call to the base classes constructor, the object is not yet of the derived type and thus the base type's implementation of the virtual function is called and not the derived type's.

    0 讨论(0)
  • 2020-11-21 06:11

    One solution to your problem is using factory methods to create your object.

    • Define a common base class for your class hierarchy containing a virtual method afterConstruction():
    class Object
    {
    public:
      virtual void afterConstruction() {}
      // ...
    };
    
    • Define a factory method:
    template< class C >
    C* factoryNew()
    {
      C* pObject = new C();
      pObject->afterConstruction();
    
      return pObject;
    }
    
    • Use it like this:
    class MyClass : public Object 
    {
    public:
      virtual void afterConstruction()
      {
        // do something.
      }
      // ...
    };
    
    MyClass* pMyObject = factoryNew();
    
    
    0 讨论(0)
提交回复
热议问题