Pure Virtual Function call from Base Ctor

╄→гoц情女王★ 提交于 2019-12-03 15:16:54

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

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.

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.

Gob00st

Which compiler are you using?

Vc10 and gcc 4.6 all compile fine. gcc give a nice warning about calling virtual function from constructor will be just using the base::bar() function instead of polymorphic.

This is probably bocs calling virtual from constructor is Undefined Behavior.

Weird C++ fact: it is legal (and, very rarely, useful) to define a pure virtual function.

You could try adding

void base::bar() { cout << "Wuh?"; }

and you will find line 2 and line 4 invoke that function.

The legal way to call that definition is to do it explicitly: base::bar();

The compiler has managed to optimise the virtual call (which will fail) to the non-virtual call in those cases. It is neither required nor prevented from doing that; all your calls have undefined behaviour.

Your code contains undefined behavior, so whatever the compiler does is correct. All of the calls to bar() in your code require dynamic resolution, and would result in a call to a pure virtual function; this is undefined behavior. (You can call Base::bar() if you write it like that and the function exists, since no dynamic resolution is required.) The fact that the code compiles doesn't mean that it will run successfully; in the case of g++, for example, I'm fairly sure that it will crash with an error message.

Whether the compiler complains or not probably depends on how much effort it goes to to resolve the dynamic resolution at compile time. Without optimization, it almost certainly can't resolve 3 at compile time, but I'm somewhat surprised that it treats 1 and 2 differently.

And the statement that "pure virtual function cannot be called from constructor" is false. The only time there is a problem is when dynamic resolution resolves to a pure virtual function. Calling it with static resolution (assuming it exists) is fine, and calling a pure virtual function in a base class is fine if the dynamic resolution turns up a non pure virtual function in a derived class whose constructor has started or has run.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!