Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pure Virtual Function call from Base Ctor

Consider the following sample code:

#include <iostream>

using namespace std;

class base
{
   public:
      base()
      {
         bar(); //Line1
         this->bar(); //Line2
         base *bptr = this; 
         bptr->bar(); //Line3
         ((base*)(this))->bar(); //Line4
      }

      virtual void bar() = 0;
};

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

int main()
{
   derived d;
}

The above code has pure virtual function bar() in base class which is overriden in the derived class. The pure virtual function bar() has no definition in base class.

Now focus on Line1, Line2, Line3 and Line4.

I understand : Line1 gives compilation error, because pure virtual function cannot be called from ctor.

Questions:

  1. Why does Line2 and Line4 give no compilation error for the same reason mentioned in I understand statement above?. The calls in Line2 and Line4 will eventually cause linker-error only.

  2. Why does Line3 give neither compilation error nor linker error but gives run-time exception only ?

Real-Life example of UB when Pure virtual function call through constructor:

Real-Life example of UB when Pure virtual function call through constructor

like image 414
nitin_cherian Avatar asked Feb 09 '12 14:02

nitin_cherian


People also ask

What is pure virtual function in C++?

A pure virtual function (or abstract function) in C++ is a virtual function for which we can have implementation, But we must override that function in the derived class, otherwise the derived class will also become abstract class (For more info about where we provide implementation for such functions refer to this https://stackoverflow.

Why can't I call virtual functions from the base class constructor?

In short, objects are constructed from the base up to the derived. So when you try to call a virtual function from the base class constructor, overriding from derived classes hasn't yet happened because the derived constructors haven't been called yet. Share Improve this answer

Why do I get a purecall error when calling a function?

Answer: You get the dreaded purecall error, because the base class constructor has engaged in a conspiracy with the function call_f to call the function f from its constructor. Since f is a pure virtual function, you get the purecall error. Okay, next question: Why didn’t the original code result in a compiler error?

What is the r6025 – pure virtual function call error?

In our discussion __purecall , we saw that you can declare a pure virtual function with the = 0 syntax, and if you try to call one of these functions from the base class, you will get the dreaded R6025 – pure virtual function call error.


3 Answers

In all four cases, the behaviour is undefined; so exactly what happens depends on what your compiler happens to do in the face of invalid input.

The compiler might attempt to diagnose the problem to give a warning; this is easy to do for Line 1, and more difficult for the other lines, which would explain why you only see a warning for Line 1.

When calling a virtual function from a constructor, the compiler knows which overload should be called, and so it might generate a static call. This is why you get a link error from Line 2 and Line 4.

In Line 3, the compiler must have decided that it's too difficult to work out whether it can generate a static call, so it generated a dynamic call instead. Tracking the value of a variable is rather harder than working out that a temporary pointer must refer to this, and often not possible at all. That's why you get a run-time error there.

Of course, all of this is undefined behaviour, and might change from compiler to compiler, or according to the phase of the moon.

If the function had an implementation, then it would be valid to call it statically, as Base::bar(), or bptr->Base::bar(). Calling it dynamically would still give undefined behaviour.

like image 83
Mike Seymour Avatar answered Nov 15 '22 02:11

Mike Seymour


Calling an Pure virtual function from constructor is an Undefined Behavior & the compiler is free to show any behavior.

Reference:
C++03 Standard 10.4/6:

"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."

The C++ standard defines Undefined behavior in:

[defns.undefined] 1.3.12 undefined behavior

behavior, such as might arise upon use of an erroneous program construct or erroneous data, for which this International Standard imposes no requirements. Undefined behavior may also be expected when this International Standard omits the description of any explicit definition of behavior. [Note: permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. ]

like image 28
Alok Save Avatar answered Nov 15 '22 04:11

Alok Save


I can partially answer. Line 3 requires that the compiler do data flow analysis to determine that the function Is not being called on another fully constructed object.

like image 28
antlersoft Avatar answered Nov 15 '22 03:11

antlersoft