3

I have an abstract base class Foo with an abstract method called bar. I'm calling bar from Foo's constructor. I'm expecting subclasses to override bar (it is abstract after all) and then Foo to call the overridden bar on every instance:

class Foo
{
    public:
        Foo() { bar(); }
        virtual void bar() = 0;
}

However, I'm getting an error:

foo.obj:-1: error: LNK2019: unresolved external symbol "protected: virtual void __cdecl Foo::bar(void)" (?bar@Foo@@MEAAXXZ) referenced in function "public: __cdecl Foo::Foo(void)" (??0Foo@@QEAA@XZ)

This kind of linker errors usually means that I've defined something but haven't declared it (or the other way around), and this seems to be the case again. Everything works just fine if I add a definition for bar like so:

void Foo::bar() {}

Is this intended error, or is it a bug in the linker? If it's intentional, why so? I can't see why couldn't I call abstract method from constructor? Only reason I think of is that base class' constructor gets called before subclass' methods get defined, but I still don't think I should get this error?

I'm using Qt Creator 2.7.0 - Based on Qt 5.0.2 (32 bit)

2 Answers2

4

Inside the constructor, the dynamic type of *this is Foo, and there is no defined function Foo::bar. Don't call virtual functions in constructors. (Unless you know what you're doing, in which case you'd know how to provide a definition.)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • As I thought... Is there a reason they've added/removed this feature? I've already defined that `Foo` has an abstract method called `bar`, why can't I call it from the constructor, since it will exist anyways? –  May 15 '13 at 20:32
  • @MarkusMeskanen: I'm afraid your question makes no sense. Think a bit harder about how C++ objects work (especially construction and destruction in the presence of base classes)... there isn't a useful notion of "feature" as you claim. – Kerrek SB May 15 '13 at 20:33
  • Sorry for my lack of knowledge... I can't instantiate an object of type `Foo`, therefore I must have a subclass which has `bar` defined in it, let's call it `SubFoo`. Now say `SubFoo *sf = new SubFoo;` would obviously be an object of `SubFoo`, which has `bar` defined. Therefore I can't understand why I can't just call `bar` from `Foo`'s constructor, since it'll always be defined. –  May 15 '13 at 20:35
  • @MarkusMeskanen: But think about the *order* of construction: First all base subobjects are constructed, then all data members, and then the constructor body executes. So while the base subobjects are being constructed, the derived object doesn't even exist yet. – Kerrek SB May 15 '13 at 20:36
  • @KerrebSB Oh, right... Damn. Is there a good way to call something on every subclass' instances, or should I just manually add `bar();` in every subclass' constructor? –  May 15 '13 at 20:39
  • @MarkusMeskanen: Post another question with your real problem. Then we can see if there's a good solution. – Kerrek SB May 15 '13 at 20:52
  • @MarkusMeskanen: What do you mean? This is a classic XY problem, so it'd be much more productive to start with Y... – Kerrek SB May 16 '13 at 14:42
  • No, this is not. I'm not having any code related to this question in any of my projects, and I really don't need a solution on how to call something for each instance (why would you want to do it anyways?). I just wanted to know why it works the way it works, and thought about asking if there's an easy solution for this as an addition. –  May 16 '13 at 15:20
  • http://stackoverflow.com/questions/8630160/call-to-pure-virtual-function-from-base-class-constructor – phyatt Jan 20 '15 at 05:30
2

Your problem is simple and yet very hard: The constructor of Foo runs before that of the derived class. Therefore, the virtual function is set to whatever Foo sets it to - which is not implemented.

You have to wait until construction is complete before you can use virtual function the way you expect, and all vtable entries are set to their most derived versions.

While it would have been possible to break construction into three parts (first the vtable is updated by each constructor, than the all initializers and finally all constructor functions are executed), the C++ standards committee has decided against this.

There are advantages to how things are done as well, other than simplicity for compiler builders: If you could access the more derived class members (by calling an overridden virtual function), they would not have been initialized (or even constructed) yet, so any function of a more derived class should not touch any non-trivial data members, which complicates everything even more than simply saying that you should not call virtual functions during construction.

danielschemmel
  • 10,885
  • 1
  • 36
  • 58