Invoking virtual function and pure-virtual function from a constructor
Asked Answered
A

4

5

When i invoke a virtual function from a base constructor, the compiler does not give any error. But when i invoke a pure-virtual function from the base class constructor, it gives compilation error.

Consider the sample program below:

#include <iostream>

using namespace std;
class base
{
   public:
      void virtual virtualfunc() = 0;
      //void virtual virtualfunc();
      base()
      {
         virtualfunc();
      }
};

void base::virtualfunc()
{
   cout << " pvf in base class\n";
}

class derived : public base
{
   public:
   void virtualfunc()
   {
      cout << "vf in derived class\n";
   }
};

int main()
{
   derived d;
   base *bptr = &d;
   bptr->virtualfunc();

   return 0;
}

Here it is seen that the pure virtual function has a definition. I expected the pure virtual function defined in base class to be invoked when bptr->virtualfunc() is executed. Instead it gives the compilation error:

error: abstract virtual `virtual void base::virtualfunc()' called from constructor

What is the reason for this?

Abdel answered 27/12, 2011 at 7:59 Comment(0)
C
10

Do not call pure virtual functions from constructor as it results in Undefined Behavior.

C++03 10.4/6 states

"Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined."

You get an compilation error because you have not defined the pure virtual function virtualfunc() in the Base class. To be able to call it, it must have an body.

Anyways, calling pure virtual functions in constructors should be avoided as it is Undefined Behavior to do so.

Cento answered 27/12, 2011 at 8:2 Comment(7)
@Als: I have defined the pure-virtual function. Still, why the compilation error?Abdel
@LinuxPenseur: Are you sure you compiled the correct code? In gcc-4.3.4 Without defintion there is error but With definition there is no error, but no error doesnt mean it is correct,it is still Undefined Behavior.Cento
@LinuxPenseur: It is Undefined Behavior according to the standard, and it is a quality of implementation to tell you before it potentially crashes at runtime. If you really want to call that function from the constructor, disable the virtual dispatch mechanism: base::virtualfunc() and that should take the error away (while making it explicit in user code what you are calling. Note that in some compilers the code in question would actually call base::virtualfunc() anyway (even if pure virtual as long as it was defined) without crashing, but that is just a different version of UB.Murk
@Als: You get an compilation error because you have not defined the pure virtual function In general, you would get a link error for a function that is not defined. In this case the compiler is performing dark magic on what UB means. For that compiler, UB means perform static dispatch if the function is known, or fail to compile if it is not known. I don't quite like that approach, as if you move the definition to a separate TU then you have two exactly equivalent programs one of which compiles and runs, while the other fails to even compile.Murk
@DavidRodríguez-dribeas: Agreed.Compiler performs a black magic here. In general, you would get a link error for a function that is not defined is true in case of normal or not pure virtual functions but As per the standard a pure virtual function is allowed to exist without a definition(which was OP's Q a few minutes prior to this one).I was trying to say that this is strange but allowed behavior,perhaps not with the apt words.Thanks for clarifying on that.Your replies are always concise and to the point.Cento
As of the potential link error in the pure virtual function case, there are two things to consider. On one side, all virtual functions except pure virtual ones are considered odr-used whether the program uses or not that particular override. That seems to indicate that since the pure virtual function is not used, it does not need to be defined. On the other hand, a pure virtual function can be explicitly odr-used (consider base::virtualfunc() in the code, and that will cause a linker error.Murk
... The problem at this point with this compiler is that it is deciding to call the pure virtual method (and use it) depending on the code that it has previously seen, which breaks the separate compilation model. The compiler behaves differently depending on the code present in a single TU, which is confusing to say the least.Murk
N
2

In C++ 11, there is a work around.

In the process of Constructor Delegation, you can, in fact, call an implementation of a pure virtual method--as long as at least one of the constructors of the class implementing that pure virtual method has been completed before the pure virtual call is invoked.

You could/should use the "final" keyword in order to ensure that the behavior for subclasses is not unpredictable.

See: C++ 11 Delegated Constructor Pure Virtual Method & Function Calls — Dangers?

#include <string>

/**************************************/
class Base
{
public:
    int sum;
    virtual int Do() = 0;

    void Initialize()
    {
        Do();
    }
    Base()
    {
    }
};

/**************************************/
// Optionally declare class as "final" to avoid
// issues with further sub-derivations.
class Derived final : public Base
{
public:

    virtual int Do() override final
    {
        sum = 0 ? 1 : sum;
        return sum / 2 ; // .5 if not already set.
    }

    Derived(const std::string & test)
        : Derived() // Ensure "this" object is constructed.
    {
        Initialize(); // Call Pure Virtual Method.
    }
    Derived()
        : Base()
    {
        // Effectively Instantiating the Base Class.
        // Then Instantiating This.
        // The the target constructor completes.
    }
};




/********************************************************************/
int main(int args, char* argv[])
{
    Derived d;
    return 0;
}
Navaho answered 4/2, 2013 at 19:1 Comment(0)
A
1

You should remember that when you are in a Base Class constructor there is no a derived class. More information:

http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5

When you are trying to invoke pure virtual function there is no implementation of it yet.

There is a lot of solutions. The easiest one is to create a another member function "init()" which you will invoke after the constructor of a base class.

Alcott answered 27/12, 2011 at 8:29 Comment(1)
Yes there are ways around this. Two stage initialization is NOT a good choice. Prefer the PIMP pattern.Commons
A
0

The compiler is not required to assume that a pointer has been set for a pure virtual function before the constructor has completed. In other words, it's not required to know that you have a definition for the function at that point. Therefore the behavior is undefined. On some compilers (MSVC) it will work as you expect, and on others it will give you the error that you are currently getting. On some others it will compile, but you will get a segmentation fault.

It's really a bad idea to call ANY virtual function from a constructor anyway, because it makes the intent of your code unclear and confusing.

Attractive answered 27/12, 2011 at 8:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.