Discussion:
Calling a pure virtual function
Adam Nielsen
2005-07-09 10:41:47 UTC
Permalink
Hi all,

I was expecting the following code snippet to work, so am I doing
something wrong, or is there an issue with GCC? I was under the
impression that this is allowed, according to
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.1

It seems like GCC initially allows it as it starts to compile okay, but
then I get an undefined reference error from the linker (because it
seems to be actually calling Base::number(), which obviously won't work
as it's a pure virtual function.)

I was only able to try this with GCC 3.2.3 (i486 target) and 3.3.6
(djgpp/msdos target) and both versions give the same error.

Thanks,
Adam.

------------------------------------------------------

#include <iostream>

using namespace std;

class Base {
public:
Base()
{
cout << "This is class " << this->number();
}

virtual int number() = 0;
};

class One: virtual public Base {
public:
int number()
{
return 1;
}
};

int main(void)
{

// Correctly fails stating Base is abstract
// Base *b = new Base();

// Won't compile giving undefined reference to Base::number()
One *o = new One();

return 0;
}
Lion Vollnhals
2005-07-09 17:47:22 UTC
Permalink
Post by Adam Nielsen
It seems like GCC initially allows it as it starts to compile okay, but
then I get an undefined reference error from the linker (because it
seems to be actually calling Base::number(), which obviously won't work
as it's a pure virtual function.)
it works for me if number() is not called in the Base constructor but in another
non-virtual Base function.


- --
Lion Vollnhals
free time linux enthusiast
Florian Weimer
2005-07-09 11:28:34 UTC
Permalink
Post by Adam Nielsen
class Base {
Base()
{
cout << "This is class " << this->number();
}
virtual int number() = 0;
};
Roughly speaking, when number() is invoked, the object still has type
Base (with a corresponding vtable). One's constructor will change the
type once the Base part has been constructed.

The following FAQ entry covers this:

http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.3
Adam Nielsen
2005-07-09 11:47:05 UTC
Permalink
Post by Florian Weimer
Roughly speaking, when number() is invoked, the object still has type
Base (with a corresponding vtable). One's constructor will change the
type once the Base part has been constructed.
Aha yes, I didn't even think of that! Thanks Florian and Lion for your
helpful answers!
Post by Florian Weimer
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.3
Hmm, I should've read just a little further... ;-)

It still makes me wonder whether GCC is reporting the correct error for
this mistake though, I would've expected a compiler error (something
along the lines of 'you can't call a pure virtual function') rather than
a linker error. Especially as GCC should be able to tell at compile
time the base constructor is calling a pure virtual function. I guess
it's treating the constructor like any other function, where this
behaviour would be permitted.

Either way, that solved the problem for me, so thanks again!

Cheers,
Adam.
Florian Weimer
2005-07-09 13:12:12 UTC
Permalink
Post by Adam Nielsen
It still makes me wonder whether GCC is reporting the correct error for
this mistake though, I would've expected a compiler error (something
along the lines of 'you can't call a pure virtual function') rather than
a linker error. Especially as GCC should be able to tell at compile
time the base constructor is calling a pure virtual function. I guess
it's treating the constructor like any other function, where this
behaviour would be permitted.
I think C++ allows for a definition for a purely abstract function
(which would be called in this case).
Lion Vollnhals
2005-07-09 17:54:59 UTC
Permalink
Post by Adam Nielsen
I was under the
impression that this is allowed, according to
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.1
See [23.3]. You aren't allowed to call the virtual function from the Base class constructor.
- --
Lion Vollnhals
free time linux enthusiast
Jonathan Wakely
2005-07-11 11:13:38 UTC
Permalink
Post by Adam Nielsen
Hi all,
I was expecting the following code snippet to work, so am I doing
something wrong, or is there an issue with GCC? I was under the
impression that this is allowed, according to
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.1
As you've discovered, FAQ 23.3 gives more detail.
Post by Adam Nielsen
It seems like GCC initially allows it as it starts to compile okay, but
then I get an undefined reference error from the linker (because it
seems to be actually calling Base::number(), which obviously won't work
as it's a pure virtual function.)
It's allowed, and will work, but you have to provide a definition for
the function. Calling number() from the base constructor calls
Base::number() so you have to define it.

GOTW 31 discusses topics related to this: http://www.gotw.ca/gotw/031.htm

GCC is doing exactly the right thing here, it's not possible to tell
that the definition of Base::number() is missing until link time.

jon

Continue reading on narkive:
Loading...