Understanding linker errors - c++

I wrote the following program with virtual functions:
struct A
{
virtual void foo() = 0;
A(){ init(); }
void init(){ foo(); }
};
struct B : A
{
virtual void foo(){ }
};
B a;
int main(){
return 0;
}
DEMO
I thought some linker-error should be ccured becuase there's no implementation of the foo was found. We got runtime error instead. Why? Why not the linker error?

The first thing you have to understand here is that a call to foo() made while the constructor of class A is active is dispatched to A::foo(), even if the full object under construction has type B and B overrides foo(). The presence of B::foo() is simply ignored.
This means that your code attempts to call A::foo(). Since A::foo() is a pure virtual function, the behavior of your code is undefined.
C++ language make no guarantees of what kind of "error" should occur in such cases. Which means that your expectations of "linker error" are completely unfounded. If a programs makes an attempt to perform a virtual call to a pure virtual function the behavior is simply undefined. That is the only thing that can be said here from the C++ language point of view.
How this undefined behavior will manifest itself in practical implementations depends on the implementation. Undefined behavior is allowed to manifest itself through compile-time errors, for example.
In your case, your program attempts to make a virtual call to pure virtual function A::foo(). In general case the compiler dispatches virtual calls dynamically, through a run-time mechanism that implements polymorphism (so called virtual method table is the most popular one). In some cases, when compiler can determine the exact type of the object used in the call, it optimizes the code and makes an ordinary direct (non-dynamic) call to a virtual function.
In practice, if a function pure virtual, its virtual method table entry contains a null pointer. A dynamic call to such function typically leads to run-time error. Meanwhile, a direct (optimized) call to such function typically leads to a compiler or linker error.
In your example the compiler did not optimize the call. It made a full-fledged dynamic call to A::foo() through the virtual method table. The null pointer in that table triggered the run-time error.
If you call your pure virtual function directly from the constructor
A() { foo(); }
a typical compiler will normally make a direct (optimized) call to foo(), which will typically lead to a linker error.

B does have an implementation of foo so there's no problem for the linker.
As far as I know, the fact that A is calling foo at a bad time is something the compiler/linker isn't required to figure out. (And although it might be simple to do such a check in this case, I'm sure we could come up with much more complicated cases that would be harder or perhaps impossible to catch.)

Your error is result of calling virtual functions from within constructors. The function called is the function in A, not more derived functions. C++ standard, section 12.7.4 states,
Member functions, including virtual functions (10.3), can be called
during construction or destruction (12.6.2). When a virtual function
is called directly or indirectly from a constructor or from a
destructor, including during the construction or destruction of the
classes non-static data members, and the object to which the call
applies is the object (call it x) under construction or destruction,
the function called is the final overrider in the constructor's or
destructor's class and not one overriding it in a more-derived class.
If the virtual function call uses an explicit class member access
(5.2.5) and the object expression refers to the complete object of x
or one of that object's base class subobjects but not x or one of its
base class subobjects, the behavior is undefined.
Now, you are cheating in your example. You are calling a normal function from your constructor and then a virtual function from your normal function. Change your code to,
struct A
{
virtual void foo() = 0;
A(){ foo(); }
};
and you'll get your error,
warning: pure virtual ‘virtual void A::foo()’ called from constructor [enabled by default]
_ZN1AC2Ev[_ZN1AC5Ev]+0x1f): undefined reference to `A::foo()'

Related

What happens when a destructor calls an abstract function

I'm having trouble understanding what's the reason for the crash in the following code :
class A {
public:
virtual ~A() { goo(); }
void goo() { absFoo(); }
virtual void absFoo() = 0;
};
class B : public A {
public:
void absFoo() { cout << "In B \n"; }
};
int main()
{
B b1;
b1.goo();
}
The main prints "In B" as expected, but in the end when it crashes, I can't debug it either, the compiler pops a weird message.
So my question is, when the destructor of A calls "goo()", does "absFoo()", crash
because we're referring to an abstract function?
Or does the compiler actually look for a definition in the derived classes? (And it doesn't exist anymore because it was destructed beforehand so it crashes)
I know that if we had called "absFoo()" directly from the destructor, the reason would have been the abstract function. But since here it's an outside function calling "absFoo()" I'm having trouble understanding the real reason.
What happens when a destructor calls an abstract function
First, let us consider what happens when a destructor calls any virtual function (the same applies to the constructor by the way): When a virtual function foo is called in the destructor of T, the call will not be dispatched dynamically to an implementation in a derived type (the lifetime of any derived object has already ended), but statically to the implementation T::foo.
If T::foo is pure virtual, then calling it without dynamic dispatch will have undefined behaviour. That is what happens when a pure virtual function is (indirectly) called in a destructor (or constructor).
Just to complement the already accepted answer, this is the documentation from cppreference.
When a virtual function is called directly or indirectly from a
constructor or from a destructor (including during the construction or
destruction of the class’s non-static data members, e.g. in a member
initializer list), and the object to which the call applies is the
object under construction or destruction, the function called is the
final overrider in the constructor’s or destructor’s class and not one
overriding it in a more-derived class.
In other words, during construction or destruction, the more-derived classes do not exist.
As the object is deconstructed, the vtable is updated to match the new status of the object.
Since you've removed the last function, the compiler will do whatever it considers fit; which in the case of a debug compilation in visual studio, will fallback to an abort reporting that a pure virtual function was called.
The vtable however is not part of the standard, it's an implementation detail, and there's no requirement for your program to crash; it's just what is considered the nicest thing to do when you've called a pure virtual function.

Pure virtual function call interesting cases

Consider the following code:
#include <iostream>
using namespace std;
class A
{
public:
virtual void f() = 0;
A(){f();}
};
void A::f() {
cout<<"A"<<endl;
}
class B:public A{
public:
void f(){cout<<"B"<<endl;}
};
int main()
{
B b;
}
In this case I directly call the virtual function from constructor and get compiler warning which says:
warning: abstract virtual 'virtual void A::f()' called from constructor.
But it executes without termination and prints A.
If I wrap the call of the function like this:
class A
{
public:
virtual void f() = 0;
A(){g();}
void g(){f();}
};
void A::f(){cout<<"A"<<endl;}
class B:public A{
public:
void f(){cout<<"B"<<endl;}
};
int main()
{
B b;
}
The compiler does not output any warning during compilation but it crushes at runtime with the following message:
pure virtual method called
terminate called without active exception
Abort
Can anybody explain the behavior of both of this cases?
§ 10.4 Abstract classes [class.abstract] / p6
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.
In brief: The effect of making a call to a pure virtual function directly or indirectly for the object being created from constructor is undefined.
A call to pure virtual member functions cannot be used from a constructor or a destructor, no matter if the call is direct or indirect, because then you end up with an undefined behavior.
The only useful example of providing the implementation of a pure virtual function is when calling it from a derived class:
struct A
{
virtual void f() = 0;
};
void A::f()
{
cout<<"A"<<endl;
}
struct B : A
{
void f()
{
A::f();
cout<<"B"<<endl;
}
};
In the first case, the compiler happens to save you by statically dispatching to A::f(), since it knows the static type of A. But it's quite right that this is horribly undefined behaviour and you shouldn't do it.
In the second case, the compiler does not statically dispatch to A::f() since the call is not in the constructor so it must dynamically dispatch it. Different ABIs handle pure virtual calls differently, but both MSVC and Itanium have a dedicated pure virtual call handler which is placed in the vtable to catch these events. This is what produces the error message you see.
From a compiler's point of view, if you look at how the function f() is invoked:
Case-1: A's ctor calls A-ctor => f() directly. Compiler knows precisely that this is the case and decides to issue a warning.
Case-2: A's ctor calls A-ctor => g() => f(). There are entirely legitimate cases of calling f() from one of the class methods. Compiler can not say that this is illegal. The callgraph could have been from * => bar() => g() -> f(), meaning the type of the object is not known. Such paths being possible, makes dynamic dispatching necessary - leading to the runtime error.
As others pointed out, this is undefined usage and compilers only go so far in detecting and warning.
Undefined behaviour means that the compiler does not have to handle the situation in any particularly defined manner.
Here your compiler, that knew the actual type of A in its constructor was able to inline in the pure virtual method rather than call it through the v-table. This is what would happen if the method were normal virtual, not pure virtual, and this would be defined behaviour.
Whilst it would be the behaviour too even via g(), the compiler did not do this for a pure virtual f() function. It doesn't have to.
The simple moral is do not invoke undefined behaviour, and if you want to call f() from the constructor do not make it pure virtual.
If you want to enforce your sub-classes to implement f(), do not call it from the constructor of A but give that function you want to call a different name. Preferably not virtual at all.

Why a virtual call to a pure virtual function from a constructor is UB and a call to a non-pure virtual function is allowed by the Standard?

From 10.4 Abstract Classes parag. 6 in the Standard :
"Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined."
Assuming that a call to a non-pure virtual function from a constructor (or destructor), is allowed by the Standard, why the difference ?
[EDIT] More standards quotes about pure virtual functions:
§ 10.4/2 A virtual function is specified pure by using a pure-specifier (9.2) in the function declaration in the class definition. A pure virtual function needs be defined only if called with, or as if with (12.4), the qualified-id syntax (5.1). ... [ Note: A function declaration cannot provide both a pure-specifier and a definition —end note ]
§ 12.4/9 A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined.
Some questions that need answering are:
Where the pure virtual function has not been given an implementation, should this not be a compiler or linker error instead?
Where the pure virtual function has been given an implementation, why can it not be well-defined in this case to invoke this function?
Because a virtual call can NEVER call a pure virtual function -- the only way to call a pure virtual function is with an explicit (qualified) call.
Now outside of constructors or destructors, this is enforced by the fact that you can never actually have objects of an abstract class. You must instead have an object of some non-abstract derived class which overrides the pure virtual function (if it didn't override it, the class would be abstract). While a constructor or destructor is running, however, you might have an object of an intermediate state. But since the standard says that trying to call a pure virtual function virtually in this state results in undefined behavior, the compiler is free to not have to special case things to get it right, giving much more flexibility for implementing pure virtual functions. In particular, the compiler is free to implement pure virtuals the same way it implements non-pure virtuals (no special case needed), and crash or otherwise fail if you call the pure virtual from a ctor/dtor.
I think this code is an example of the undefined behaviour referenced by the standard. In particular, it is not easy for the compiler to notice that this is undefined.
(BTW, when I say 'compiler', I really mean 'compiler and linker'. Apologies for any confusion.)
struct Abstract {
virtual void pure() = 0;
virtual void foo() {
pure();
}
Abstract() {
foo();
}
~Abstract() {
foo();
}
};
struct X : public Abstract {
virtual void pure() { cout << " X :: pure() " << endl; }
virtual void impure() { cout << " X :: impure() " << endl; }
};
int main() {
X x;
}
If the constructor of Abstract directly called pure(), this would obviously be a problem and a compiler can easily see that there is no Abstract::pure() to be called, and g++ gives a warning. But in this example, the constructor calls foo(), and foo() is a non-pure virtual function. Therefore, there is no straightforward basis for the compiler or linker to give a warning or error.
As onlookers, we can see that foo is a problem if called from the constructor of Abstract. Abstract::foo() itself is defined, but it tries to call Abstract::pure and this doesn't exist.
At this stage, you might think that the compiler should issue a warning/error about foo on the grounds that it calls a pure virtual function. But instead you should consider the derived non-abstract class where pure has been given an implementation. If you call foo on that class after construction (and assuming you haven't overriden foo), then you will get well-defined behaviour. So again, there is no basis for a warning about foo. foo is well-defined as long as it isn't called in the constructor of Abstract.
Therefore, each method (the constructor and foo) are each relatively OK if you look on them on their own. The only reason we know there is a problem is because we can see the big picture. A very smart compiler would put each particular implementation/non-implementation into one of three categories:
Fully-defined: It, and all the methods it calls are fully-defined at every level in the object hierarchy
Defined-after-construction. A function like foo that has an implementation but which might backfire depending on the status of the methods it calls.
Pure virtual.
It's a lot of work to expect a compiler and linker to track all this, and hence the standard allows compilers to compile it cleanly but give undefined behaviour.
(I haven't mentioned the fact that it is possible to give implementations to pure-virtual methods. This is new to me. Is it defined properly, or is it just a compiler-specific extension? void Abstract :: pure() { })
So, it's not merely undefined 'because the standard says so`. You have to ask yourself 'what behaviour would you define for the above code?'. The only sensible answer is either to leave it undefined or to mandate a run-time error. The compiler and linker won't find it easy to analyse all these dependencies.
And to make matters worse, consider pointers-to-member-functions! The compiler or linker can't really tell if the 'problematic' methods will ever be called - it might depend on a whole load of other things that happen at runtime. If the compiler sees (this->*mem_fun)() in the constructor, it can't be expected to know how well-defined mem_fun is.
It is the way the classes are constructed and destructed.
Base is first constructed, then Derived. So in the constructor of Base, Derived has not yet been created. Therefore none of its member functions can be called. So if the constructor of Base calls a virtual function, it can't be the implementation from Derived, it must be the one from Base. But the function in Base is pure virtual and there is nothing to call.
In destruction, first Derived is destroyed, then Base. So once again in the destructor of Base there is no object of Derived to invoke the function, only Base.
Incidentally it is only undefined where the function is still pure virtual. So this is well-defined:
struct Base
{
virtual ~Base() { /* calling foo here would be undefined */}
virtual void foo() = 0;
};
struct Derived : public Base
{
~Derived() { foo(); }
virtual void foo() { }
};
The discussion has moved on to suggest alternatives that:
It might produce a compiler error, just like trying to create an instance of an abstract class does.
The example code would no doubt be something like:
class Base
{
// other stuff
virtual void init() = 0;
virtual void cleanup() = 0;
};
Base::Base()
{
init(); // pure virtual function
}
Base::~Base()
{
cleanup(); // which is a pure virtual function. You can't do that! shouts the compiler.
}
Here it is clear what you are doing is going to get you into trouble. A good compiler might issue a warning.
it might produce a link error
The alternative is to look for a definition of Base::init() and Base::cleanup() and invoke that if it exists, otherwise invoke a link error, i.e. treat cleanup as non-virtual for the purpose of constructors and destructors.
The issue is that won't work if you have a non-virtual function calling the virtual function.
class Base
{
void init();
void cleanup();
// other stuff. Assume access given as appropriate in examples
virtual ~Base();
virtual void doinit() = 0;
virtual void docleanup() = 0;
};
Base::Base()
{
init(); // non-virtual function
}
Base::~Base()
{
cleanup();
}
void Base::init()
{
doinit();
}
void Base::cleanup()
{
docleanup();
}
This situation looks to me to be beyond the capability of both the compiler and linker. Remember that these definitions could be in any compilation unit. There is nothing illegal about the constructor and destructor calling init() or cleanup() here unless you know what they are going to do, and there is nothing illegal about init() and cleanup() calling the pure virtual functions unless you know from where they are invoked.
It is totally impossible for the compiler or linker to do this.
Therefore the standard must allow the compile and link and mark this as "undefined behaviour".
Of course if an implementation does exist, the compiler is free to use it if able. Undefined behaviour doesn't mean it has to crash. Just that the standard doesn't say it has to use it.
Note that this case the destructor is calling a member function that calls the pure virtual but how do you know it will do even this? It could be calling something in a completely different library that invokes the pure virtual function (assume access is there).
Base::~Base()
{
someCollection.removeMe( this );
}
void CollectionType::removeMe( Base* base )
{
base->cleanup(); // ouch
}
If CollectionType exists in a totally different library there is no way any link error can occur here. The simple matter is again that the combination of these calls is bad (but neither one individually is faulty). If removeMe is going to be calling pure-virtual cleanup() it cannot be called from Base's destructor, and vice-versa.
One final thing you have to remember about Base::init() and Base::cleanup() here is that even if they have implementations, they are never called through the virtual function mechanism (v-table). They would only ever be called explicitly (using full class-name qualification) which means that in reality they are not really virtual. That you are allowed to give them implementations is perhaps misleading, probably wasn't really a good idea and if you wanted such a function that could be called through derived classes, perhaps it is better being protected and non-virtual.
Essentially: if you want the function to have the behaviour of a non-pure virtual function, such that you give it an implementation and it gets called in the constructor and destructor phase, then don't define it as pure virtual. Why define it as something you don't want it to be?
If all you want to do is prevent instances being created you can do that in other ways, such as:
- Make the destructor pure virtual.
- Make the constructors all protected
Before discussing why it's undefined, let's first clarify what the question is about.
#include<iostream>
using namespace std;
struct Abstract {
virtual void pure() = 0;
virtual void impure() { cout << " Abstract :: impure() " << endl; }
Abstract() {
impure();
// pure(); // would be undefined
}
~Abstract() {
impure();
// pure(); // would be undefined
}
};
struct X : public Abstract {
virtual void pure() { cout << " X :: pure() " << endl; }
virtual void impure() { cout << " X :: impure() " << endl; }
};
int main() {
X x;
x.pure();
x.impure();
}
The output of this is:
Abstract :: impure() // called while x is being constructed
X :: pure() // x.pure();
X :: impure() // x.impure();
Abstract :: impure() // called while x is being destructed.
The second and third lines are easy to understand; the methods were originally defined in Abstract, but the overrides in X take over. This result would have been the same even if x had been a reference or pointer of Abstract type instead of X type.
But this interesting thing is what happens inside the constructor and destructor of X. The call to impure() in the constructor calls Abstract::impure(), not X::impure(), even though the object being constructed is of type X. The same happens in the destructor.
When an object of type X is being constructed, the first thing that is constructed is merely an Abstract object and, crucially, it is ignorant of the fact that it will ultimately be an X object. The same process happens in reverse for the destruction.
Now, assuming you understand that, it is clear why the behaviour must be undefined. There is no method Abstract :: pure which could be called by the constructor or destructor, and hence it wouldn't be meaningful to try to define this behaviour (except possibly as a compilation error.)
Update: I've just discovered that is possible to give an implementation, in the virtual class, of a pure virtual method. The question is: Is this meaningful?
struct Abstract {
virtual void pure() = 0;
};
void Abstract :: pure() { cout << "How can I be called?!" << endl; }
There will never be an object whose dynamic type is Abstract, hence you'll never be able to execute this code with a normal call to abs.pure(); or anything like that. So, what is the point of allowing such a definition?
See this demo. The compiler gives warnings, but now the Abstract::pure() method is callable from the constructor. This is the only route by which Abstract::pure() can be called.
But, this is technically undefined. Another compiler is entitled to ignore the implementation of Abstract::pure, or even to do other crazy things. I'm not aware of why this isn't defined - but I wrote this up to try to help clear up the question.

Should virtual dispatch happen when a virtual method is called within a virtual method using object?

struct B
{
virtual void bar () {}
virtual void foo () { bar(); }
};
struct D : B
{
virtual void bar () {}
virtual void foo () {}
};
Now we call foo() using an object of B as,
B obj;
obj.foo(); // calls B::bar()
Question:
Should bar() will be resolved through virtual dispatch or it will be resolved using the static type of the object (i.e. B).
EDIT: I think I misunderstood your question. I'm pretty sure it depends on how smart the compiler's optimizer is. A naive implementation would of course still go through a virtual lookup. The only way to know for sure for a particular implementation is to compile the code and look at the disassembly to see if it's smart enough to make the direct call.
Original answer:
It will be virtually dispatched. This is more obvious when you consider that within a class method, a method call works out to something like this->bar();, making it obvious that a pointer is used to call the method, allowing to use the dynamic object type.
However in your example since you created a B it will of course call B's version of the method.
Do note (as seen in a comment) that virtual dispatch doesn't happen inside constructors even using the implicit this->.
EDIT2 for your update:
That's not right at all. Calls within B::foo() cannot be generally bound statically (unless due to inlining the compiler knows the static type of the object). Just because it knows that it's being called on a B* says nothing about the real type of the object in question - it could be a D* and need virtual dispatch.
It must be a virtual call. The code that you're compiling cannot know if there's not a more-derived class that it actually is that has overridden the other function.
Note that this assumes that you're compiling these separately. If the compiler inlines the call to foo() (due to its static type being known) it'll also inline the call to bar().
Answer: from the language point of view call to bar() inside B::foo() is resolved through virtual dispatch.
The bottom line is that from the point of view of C++ language, virtual dispatch always happens when you call a virtual method using its non-qualified name. When you use a qualified name of the method, the virtual dispatch does not happen. That means that the only way to suppress virtual dispatch in C++ is to use this syntax
some_object_ptr->SomeClass::some_method();
some_object.SomeClass::some_method();
In this case the dynamic type if the object on the left-hand side is ignored and the specific method is called directly.
In all other cases virtual dispatch does happen, as far as the language is concerned. I.e. the call is resolved in accordance with the dynamic type of the object. In other words, from the formal point of view, every time you call a virtual method through an immediate object, as in
B obj;
obj.foo();
the method is called through the "virtual dispatch" mechanism, regardless of context ("within a virtual method" or not - doesn't matter).
That's how it is in C++ language. Everything else is just optimizations made by compilers. As you probably know, most (if not all) compilers will generate a non-virtual call to a virtual method, when the call is performed through an immediate object. This is, of course, an obvious optimization, since the compiler knows that the static type of the object is the same as its dynamic type. Again, it doesn't depend on the context ("within a virtual method" or not - doesn't matter).
Inside a virtual method, the call can be made without specifying an object on the left hand side (as in your example), which really implies all calls have this-> implicitly present on the left. The very same rules apply in this case as well. If you just call bar(), it stands for this->bar() and the call is dispatched virtually. If you call B::bar(), it stands for this->B::bar() and the call is dispatched non-virtually. Everything else will only depend on the optimization capabilities of the compiler.
What you are trying to say by "because, once you are inside B::foo(), it's sure that this is of type B* and not D*" is totally unclear to me. This statement misses the point. Virtual dispatch depends on the dynamic type of the object. Note: it depends on the type of *this, not on the type of this. It doesn't matter at all what the type of this is. What matters is the dynamic type of *this. When you are inside B::foo, it is still perfectly possible that the dynamic type of *this is D or something else. For which reason, the call to bar() has to be resolved dynamically.
Entirely up to the implementation. Nominally it's a virtual call, but you're not entitled to assume that the emitted code will actually perform an indirection through a vtable or similar.
If foo() is called on some arbitrary B*, then of course the code emitted for foo() needs to make a virtual call to bar(), since the referand might belong to a derived class.
This isn't an arbitrary B*, this is an object of dynamic type B. The result of a virtual or non-virtual call is exactly the same, so the compiler can do what it likes ("as-if" rule), and a conforming program can't tell the difference.
Specifically in this case, if the call to foo is inlined, then I'd have thought that the optimizer has every chance of de-virtualizing the call to bar inside it, since it knows exactly what's in the vtable (or equivalent) of obj. If the call isn't inlined, then it's going to use the "vanilla" code of foo(), which of course will need to do some kind of indirection since it's the same code used when the call is made on an arbitrary B*.
In this case:
B obj;
obj.foo(); // calls B::bar()
the compiler can optimize away the virtual dispatch since it knows that type of the actual object is B.
However, inside of B::foo() the call to bar() needs to use virtual dispatch generally (though the compiler might be able to inline the call and for that particular call instance could possibly optimize the virtual dispatch away again). Specifically, this statement you proposed:
Irrespective of foo() is called using object or pointer/reference, all the calls inside any virtual B::foo() should be statically resolved. Because, once you are inside B::foo(), it's sure that this is of type B* and not D*
is not true.
Consider:
struct D2 : B
{
// D2 does not override bar()
virtual void foo () {
cout << "hello from D2::bar()" << endl;
}
};
Now if you had the following somewhere:
D2 test;
B& bref = test;
bref.foo();
That call to foo() would end up in B::foo(), but when B::foo() calls bar(), it needs to dispatch to D2::bar().
Actually, now that I've typed this out, the B& is completely unnecessary for this example.

Pure Virtual Function called error

I find this strange. In the ctor of Sample_Base, I call bar() which internally calls fun() which is a pure virtual function. I get the error "pure virtual function" called. Which is fine. Now, if I call fun() directly from Sample_Base's ctor, I don't get that error. I tried it on VC++ 2010 Beta 2 and on g++ 4.4.1 on Ubuntu 9.10. I agree that giving an implementation for pure virtual function, other than pure virtual destructor, is meaningless. But, I am a bit surprised about this behaviour.
class Sample_Base
{
public:
Sample_Base()
{
bar();
// fun();
}
/* This is code does not throw any error.
Sample_Base()
{
fun();
}
*/
void bar()
{
fun();
}
virtual void fun() = 0;
virtual ~Sample_Base();
};
Sample_Base::~Sample_Base()
{
}
void Sample_Base::fun()
{
std::cout << "Sample_Base::fun\n";
}
class Sample_Derived : public Sample_Base
{
public:
Sample_Derived() : Sample_Base()
{
fun();
}
void fun()
{
std::cout << "Sample_Derived::fun\n";
}
~Sample_Derived()
{
}
};
When you call the function directly, since you are in the constructor, the compiler resolves the static type of your object (Sample_Base) and calls Sample_Base::fun() directly. Since you provided an implementation for it, the compiler finds the function and it works.
When you call it indirectly, through bar(), the compiler must use the dynamic type, so it does a virtual call that gets resolved at runtime. And there it fails, because it calls a pure virtual function.
So the difference is in the moment it binds the function to the call.
Providing a definition for a pure virtual function is not necessarily meaningless. Marking a virtual function pure means that the enclosing class is abstract and that any class that derives from it is abstract unless the final override for that function is not a pure virtual function. A pure virtual function can still be called via an explicit non-virtual call.
In the body of a base class constructor (but not from a ctor-initializer) the version of a virtual function called through a virtual call is one defined in the class itself or one of its bases and not of any class overriding it (which would not yet have been constructed). This is specified explicitly in 12.7 [class.cdtor]/3.
It is legal to call a pure virtual function explicitly in a constructor body (i.e. using an explicit class qualifier) - although this would required the function to have a body defined - but it is undefined behaviour to call a pure virtual function via a virtual call which is only possible from the constructor or destructor of an abstract class. This is specified explicitly in 10.4 [class.abstract]/6.
At construction time, when the Sample_Base constructor is called, the object is not fully constructed yet. Specifically the parts belonging to Sample_Derived are not yet created calls to virtual functions that would be overwritten by Sample_Derived will not call the implementation in Sample_Derived, but the version defined in Sample_Base. And since the function has no implementation there you get an error.
For more information and possible workarounds also see this entry in the C++ FAQ Lite.
Calling a virtual function won't call the overriding functions in the derived classes. Calling a pure virtual function in a constructor or destructor is Undefined behavior.
You might be interested in reading this and this.
This behavior is not undefined, it's explicitly defined: virtual functions are not virtual in constructors and destructors. They call the static version of the function. If the function is pure virtual, this results in the famous "pure virtual call" error in VC.
I've seen an amusing variation of this in a multithreaded program: an object is being destructed on thread A, while thread B is attempting to call a virtual function. There was no virtual function call in the constructor or destructor, but we still got hit with a pure virtual call error.