Calling virtual functions inside constructors

前端 未结 13 1070

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:12

    Other answers have already explained why virtual function calls don't work as expected when called from a constructor. I'd like to instead propose another possible work around for getting polymorphic-like behavior from a base type's constructor.

    By adding a template constructor to the base type such that the template argument is always deduced to be the derived type it's possible to be aware of the derived type's concrete type. From there, you can call static member functions for that derived type.

    This solution does not allow non-static member functions to be called. While execution is in the base type's constructor, the derived type's constructor hasn't even had time to go through it's member initialization list. The derived type portion of the instance being created hasn't begun being initialized it. And since non-static member functions almost certainly interact with data members it would be unusual to want to call the derived type's non-static member functions from the base type's constructor.

    Here is a sample implementation :

    #include <iostream>
    #include <string>
    
    struct Base {
    protected:
        template<class T>
        explicit Base(const T*) : class_name(T::Name())
        {
            std::cout << class_name << " created\n";
        }
    
    public:
        Base() : class_name(Name())
        {
            std::cout << class_name << " created\n";
        }
    
    
        virtual ~Base() {
            std::cout << class_name << " destroyed\n";
        }
    
        static std::string Name() {
            return "Base";
        }
    
    private:
        std::string class_name;
    };
    
    
    struct Derived : public Base
    {   
        Derived() : Base(this) {} // `this` is used to allow Base::Base<T> to deduce T
    
        static std::string Name() {
            return "Derived";
        }
    };
    
    int main(int argc, const char *argv[]) {
    
        Derived{};  // Create and destroy a Derived
        Base{};     // Create and destroy a Base
    
        return 0;
    }
    

    This example should print

    Derived created
    Derived destroyed
    Base created
    Base destroyed
    

    When a Derived is constructed, the Base constructor's behavior depends on the actual dynamic type of the object being constructed.

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

    I am not seeing the importance of the virtual key word here. b is a static-typed variable, and its type is determined by compiler at compile time. The function calls would not reference the vtable. When b is constructed, its parent class's constructor is called, which is why the value of _n is set to 1.

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

    Calling virtual functions from a constructor or destructor is dangerous and should be avoided whenever possible. All C++ implementations should call the version of the function defined at the level of the hierarchy in the current constructor and no further.

    The C++ FAQ Lite covers this in section 23.7 in pretty good detail. I suggest reading that (and the rest of the FAQ) for a followup.

    Excerpt:

    [...] In a constructor, the virtual call mechanism is disabled because overriding from derived classes hasn’t yet happened. Objects are constructed from the base up, “base before derived”.

    [...]

    Destruction is done “derived class before base class”, so virtual functions behave as in constructors: Only the local definitions are used – and no calls are made to overriding functions to avoid touching the (now destroyed) derived class part of the object.

    EDIT Corrected Most to All (thanks litb)

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

    The vtables are created by the compiler. A class object has a pointer to its vtable. When it starts life, that vtable pointer points to the vtable of the base class. At the end of the constructor code, the compiler generates code to re-point the vtable pointer to the actual vtable for the class. This ensures that constructor code that calls virtual functions calls the base class implementations of those functions, not the override in the class.

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

    The reason is that C++ objects are constructed like onions, from the inside out. Base classes are constructed before derived classes. So, before a B can be made, an A must be made. When A's constructor is called, it's not a B yet, so the virtual function table still has the entry for A's copy of fn().

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

    Firstly,Object is created and then we assign it 's address to pointers.Constructors are called at the time of object creation and used to initializ the value of data members. Pointer to object comes into scenario after object creation. Thats why, C++ do not allows us to make constructors as virtual . .another reason is that, There is nothing like pointer to constructor , which can point to virtual constructor,because one of the property of virtual function is that it can be used by pointers only.

    1. Virtual functions are used to assign value dynamically,as constructors are static,so we can not make them virtual.
    0 讨论(0)
提交回复
热议问题