none
Using polymorphism in base class constructor

    General discussion

  • Hi,

    I've got a code where I create virtual method in base class and the same method in sub-class:

    /* In base class */
    
    virtual double wartosc(unsigned int x) const /* Wartość zmiennej losowej dla zdarzenia x */
    {
    		return(x); /* Standardowo F(x)=x */
    }	
    
    /* In sub-class */
    
    double wartosc(unsigned int x) const
    {
    	return(-(double)x);
    }

    Now I've got sub-class constructor which calls base-class constructor. The base class constructor calls this method. I expect it to call the sub-class method, but it calls the base class method.

    /* Base-class constructor */
    
    ZmiennaLosowa(RozkladPrawdopodobienstwa* r) : rozklad(r), dlugosc(r->dlugosc())
    {
       /* I call this method "wartosc" here */
    }
    
    /* Sub-class constructor */
    
    Kwadrat(RozkladPrawdopodobienstwa* r) : ZmiennaLosowa(r)
    {
    		
    }

    Additionally if I make the method in base class - pure virtual, the code fails with abort().

    Tuesday, April 23, 2019 4:57 PM

All replies

  • Try using 'override' when defining the sub-class method.
    Tuesday, April 23, 2019 5:05 PM
  • Try using 'override' when defining the sub-class method.

    Hi, thank you for suggestion. Adding 'override' didn't change the behaviour. The base-class virtual method is called.

    Is such use of polymorphism correct, or did I do something wrong? Should I change my program?

    Tuesday, April 23, 2019 5:17 PM
  • Is such use of polymorphism correct, or did I do something wrong?

    Unfortunately, you did something wrong. Although I can understand why this caught you out.

    C++ layers the class construction and destruction.

    For example:

    #include <iostream>
    
    class base
    {
    public:
    	base()
    	{
    		print();
    	}
    
    	~base()
    	{
    		print();
    	}
    
    	virtual void print()
    	{
    		std::cout << "In base\n";
    	}
    };
    
    class derived : public base
    {
    public:
    	derived()
    	{
    		print();
    	}
    
    	~derived()
    	{
    		print();
    	}
    
    	virtual void print() override
    	{
    		std::cout << "In derived\n";
    	}
    };
    
    int main()
    {
    	derived d;
    
    	return 0;
    }

    This will output:

    In base
    In derived
    In derived
    In base

    As you should know, if you don't tell a derived class' constructor what base constructor to call, it will default to the default constructor for that class. So the order that the constructors are called are base::base() then derived::derived(). The order that the destructors are called are the inverse of the constructors, so derived::~derived() then base::~base().

    During the base::base() constructor, the type of the class is actually seen as base, not derived. The vtable is set up as the base vtable so all virtual calls will go to the base versions. It is only when derived::derived() is called that the type of the class is seen as derived and the vtable is updated to point to the derived versions of the functions.

    When the destructor is called, this goes in reverse. During derived::~derived() the type of the class is seen as derived, but after this finishes, base::~base is called and then the type of the class is seen as base.

    This is actually the reason why virtual member function calls are discouraged in constructors and destructors.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Tuesday, April 23, 2019 10:15 PM
  • Thank you for detailed answer and explanation!

    Regards.

    Wednesday, April 24, 2019 5:48 AM
  • Try another C++ — “C++/CLR”. Then the base constructor of a ‘ref class’ will call the derived virtual function.

    Wednesday, April 24, 2019 6:31 AM