-->

Invoking virtual function and pure-virtual functio

2019-02-10 13:42发布

问题:

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?

回答1:

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.



回答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;
}


回答3:

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.



回答4:

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.