I've come across quite weird scenario today. When directly calling a pure virtual method in Interface constructor, I get a undefined reference error.
class Interface
{
public:
virtual void fun() const = 0;
Interface(){ fun(); }
};
class A : public Interface
{
public:
void fun() const override {};
};
int main()
{
A a;
}
Results in:
prog.cc: In constructor 'Interface::Interface()':
prog.cc:5:22: warning: pure virtual 'virtual void Interface::fun() const' called from constructor
5 | Interface(){ fun(); }
| ^
/tmp/ccWMVIWG.o: In function `main':
prog.cc:(.text.startup+0x13): undefined reference to `Interface::fun() const'
collect2: error: ld returned 1 exit status
However, wrapping a call to fun() in a different method like this:
class Interface
{
public:
virtual void fun() const = 0;
Interface(){ callfun(); }
virtual void callfun()
{
fun();
}
};
class A : public Interface
{
public:
void fun() const override {};
};
int main()
{
A a;
}
Compiles just fine and (obviously) crashes with pure virtual call error. I've tested it on latest GCC 8.2.0 and 9.0.0 and Clang 8.0.0. Out of those, only GCC produces a linker error in the first case.
Wandbox links for a full working example with the error:
EDIT: I'm getting flagged for duplication, but I'm not sure how this question is duplicated. It doesn't have anything to do with dangers of calling pure virtual method (from constructor or whatnot), I'm aware of them.
I was trying to understand why the compiler permits this call in one scenario, and fails to do so in another, which was explained very well by Adam Nevraumont.
EDIT2:
It seems, that even if callFun
is not virtual, it still somehow prevents GCC from devirtualizing and inlining fun
call. See the example below:
class Interface
{
public:
virtual void fun() const = 0;
Interface(){ callfun(); }
void callfun()
{
fun();
}
};
class A : public Interface
{
public:
void fun() const override {};
};
int main()
{
A a;
}