Pure virtual function call

Possible duplicate:
Calling virtual functions inside constructors

Take a look at this code. In the constructor of the base class, we can call a pure virtual function using the 'this' pointer. Now that I want to create a typed pointer to the same class and casting 'this' to the same type. It throws a “pure virtual function exception” exception. Why is this so?

#include <iostream> using namespace std; class Base { private: virtual void foo() = 0; public: Base() { //Uncomment below 2 lines and it doesn't work (run time exception) //Base * bptr = (Base*)this; //bptr->foo(); //This call works this->foo(); } }; void Base::foo() { cout << "Base::foo()=0" << endl; } class Der : public Base { public: Der() { } public: void foo() { cout << "Der::foo()" << endl; } }; int main() { cout << "Hello World!" << endl; Der d; } 
+4
source share
2 answers

You should never call virtual functions inside the constructor .

Virtual functions are not sent as you think. Rather, during construction, the dynamic type of the underlying base subobject being created is the base type, and thus the function is sent to the base function (which is purely virtual in your case).

Just don't do it.

(The reason is obvious: when constructing a derived object, the base subobject must be built first, so an environment-based object does not even exist during the base construction.)


Edit: Here are some more explanations. Compilers are fine-tuned and encouraged to static send virtual if they can. In this case, it is determined at compile time, to which the actual function will be called. This happens when you say foo() or this->foo() in the Base constructor or when you say x.Base::foo() in some other context, where Derived x; - your object. When sending occurs statically, either the Base::foo() implementation is called directly, or you get a linker error if there is no implementation.

On the other hand, if sending is dynamic, that is, at run time, there is a possibility, albeit unusual, that the sending actually ends up with Base::foo() selected as the final target. This cannot happen under “normal” conditions, since the compiler will not allow you to instantiate a class with purely virtual functions, and therefore the purpose of the usual dynamic dispatch is always a function for which an implementation must exist (or at least you’d get an error linker if you are not linking it).

But there is another situation that stands in this question: the compiler decides to perform dispatching at runtime, for some reason, and the initial speed ends with a pure virtual function. In this case, your program terminates. It does not matter whether this function is implemented or not, but it simply does not have an entry in the hierarchy of polymorphic classes (consider it a "null pointer in vtable", therefore, = 0 ). For this to happen, the dynamic type of the object must be an abstract base class type, and the dispatcher must happen dynamically. The former can only be achieved in the base constructor of the derived object, and the latter requires that you convince the compiler not to send the call statically. There is a difference between this->foo() (static) and Base * p = this; p->foo(); Base * p = this; p->foo(); (dynamic). (Also compare this to x.Base::foo() , which is sent statically.)

All this is just a consequence of the implementation and is covered with a blanket “w90 behavior”, of course. If you want to take away one thing from him, then dynamic sending cannot find a pure virtual function. And, of course, you should never call virtual functions inside the constructor.

+15
source

This is the wrong procedure for what you are probably trying to do.

You need a 2-phase construction, and for this you must use the factory object, which creates the class and then calls the virtual method on it.

You can actually call an unclean virtual function from a constructor or destructor, but then you should know that what will be called is a method from the class itself, and not something polymorphic.

Calling a pure virtual function from the constructor is undefined behavior. This will take place whenever your class is created, regardless of whether it calls it directly from the constructor (which the compiler can catch and warn) or from the method that calls your constructor call (which potentially goes beyond the scope of the compiler or linker for detection).

+1
source

Source: https://habr.com/ru/post/1399327/


All Articles