I was given this piece of code to analyze and point out what’s wrong with it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
struct Base { Base() { bar(); } virtual void foo() = 0; void bar() { foo(); } }; struct Derived final : public Base { virtual void foo() override {} }; int main(int argc, char** argv) { Derived d; return 1; } |
I was also able to compile and execute this program on my Mac; output from Xcode gives away the answer:
libc++abi.dylib: Pure virtual function called!
Program output.
Program ended with exit code: 9
But why? The constructor of
Base calls
void bar(), which in turn calls pure
virtual void foo() = 0. The
Derived overrides
foo() so what’s the problem here?
Inside the constructor of
Base, the type of
this pointer is…
Base. So the call to
foo() inside
bar() resolved to
Base version of
foo(), which is a pure virtual function lacking implementation. This is illegal and the compiler puts a check inside
Base::foo() virtual function table pointing to
__cxa_pure_virtual. That in turn calls
__pthread_kill terminating the program.
__cxa_pure_virtual disassembly:
1 2 3 4 5 6 |
libc++abi.dylib`__cxa_pure_virtual: 0x7fff723e8730 <+0>: pushq %rbp 0x7fff723e8731 <+1>: movq %rsp, %rbp 0x7fff723e8734 <+4>: leaq 0x1f2f(%rip), %rdi ; "Pure virtual function called!" 0x7fff723e873b <+11>: xorl %eax, %eax 0x7fff723e873d <+13>: callq 0x7fff723dc14a ; abort_message |
UPDATE:
Related discussion: C++ corner case: You can implement pure virtual functions in the base class.
The “why” in this question is that C++ is more type safe than languages like Java and C# with respect to object construction. There is no possibility, as in those languages, of accessing not yet initialized stuff down in the most (or more) derived class.
More that’s wrong with the code: in class
Derived
the keywords
public
and
virtual
are superfluous and should be omitted. Also the
final
keyword should probably be omitted, it’s wrong as a default. The arguments to
main
are declared but not used, and may cause undesired warning diagnostics.
main
returns
1
, which in practice is OK but indicates failure, and is not a standard-supported value. I think these issues are more serious, since they’re usually not diagnosed by the compiler or runtime support.
After all, source code is mostly about communicating to humans, and all that redundant stuff just distracts.
I disagree regarding the keywords. They more explicitly state the intent of the programmer. I know from the compiler stand point they’re not needed, but I like to put them in my code to quickly see, for example, that the derived class overrides a virtual function, inherits publicly from Base, etc, etc. But I guess we’re really discussing style at this point 🙂
You see the overriding from the
override
keyword.
You see the public inheritance and access from the
struct
keyword.
Adding to that is completely redundant, just noise IMO.
I think it helps the newcomers to C++ see the stated intent more clearly. I agree that non of those keywords are needed, but how many new C++ developers know for example that the only difference between
struct
and
class
is the default visibility? I personally prefer ALL keywords that can be in place to be in place. But again, we’re really discussing style, not validity of code.
Nobody has mentioned that Base does not have a virtual destructor.