Legally invoking a pure virtual function
Asked Answered
R

4

10

I'm sure we've all seen code that crashes due to a bug that results in a pure virtual function being called. One simple example is like this:

struct Base
{
    Base() { method(); }

    virtual void method() = 0;
};

struct Derived : Base
{
    void method() {};
};

int main()
{
    Derived d;
}

In this case, the call to method() in the Base constructor is specifically cited as undefined behaviour by section 10.4/6 of the C++ standard, so it's no surprise that we end up crashing. (Both g++ and Clang warn about this, and in fact linking fails with g++ with this example, though Clang succeeds.)

But, just for fun, can anybody come up with a way to invoke a pure virtual function which does not rely on undefined behaviour?

(I suppose you could argue that if such a method exists then there's a defect in the C++ standard, but I'm just curious...)

EDIT: Several answers guys and thank you, but I should have made it clear that I realise it's legal to make a non-virtual call to a pure virtual function (providing a definition exists somewhere). I was more wondering whether there is any clever loophole in the laws which could result in a virtual call, and thus most likely a crash in the common case of having no definition.

For example, perhaps via multiple inheritance one could perform some clever (legal) cast, but end up with the "wrong" (unimplemented) PV method() being called, that sort of thing. I just thought it was a fun brainteaser :-)

Roter answered 6/2, 2014 at 10:7 Comment(10)
Looks like a good candidate for the language-lawyer tag, but you're at 5 already. You might consider re-tagging.Ethnomusicology
@Angew good call, changedRoter
Well, there is nothing that prevents you from implementing that pure virtual function, and then its called from that ctor context just fine.Corotto
Three words: pure virtual destructor. Google it.Unravel
@PlasmaHH, but would it be a pure virtual function anymore if it is implemented in the base class?Hysterics
@user2079303 Yes. As long as it's = 0, it's a pure virtual function and causes the class containing it to be abstract.Ethnomusicology
Angew: Ok, good to know. @Tristan, Are you asking specifically "How to invoke a pure virtual function inside a constructor?" (Which you cite as UB) or just "How to invoke pure virtual function from the Base class?" which you can do outside constructor just fine as I understand.Hysterics
@Angew: The example above was just the first way that came to mind to call a PV method, I'm not specifically asking about constructors. In fact, I should have made clear that I meant unimplemented PV functions; basically the question comes down to "can you trick the runtime into calling an unimplemented PV function (and thus crashing) without breaking any rules?"Roter
@PlasmaHH: It's not "called from that ctor context just fine"; it's still undefined behaviour to call it virtually.Ossy
@TristanBrindle I don't really understand your amended question. You already found where the standard says that a virtual call to a pure virtual function during construction and destruction is UB. A class with pure virtual functions is abstract and cannot be constructed, so other than during construction and destruction of a derived class, it seems obvious that a virtual call can never resolve to a pure virtual function, and that'll be why the answers focus on non-virtual calls. If you take non-virtual calls out of the picture, there's nothing left, is there?Respirator
O
5

It's perfectly legal to call a pure virtual function non-virtually:

Derived d;
d.Base::method();

Of course, this requires the function to be defined, which isn't the case in your example.

Ossy answered 6/2, 2014 at 10:37 Comment(0)
E
2

Depends on what you mean with possible. Here's one which compiles successfully, but will most likely result in a linker error:

struct Base
{
    virtual void method() = 0;
};

struct Derived : Base
{
    void method() { Base::method(); };
};

int main()
{
  Derived d;
  d.method();
}

Live example

It compiles because nothing prevents a pure virtual function from actually having a body as well. That can be provided in the same translation unit (in a separate definition), or in a different translation unit. That's why it's a linker error and not a compiler one - just that the function has no body here doesn't mean it doesn't have one elsewhere.

Ethnomusicology answered 6/2, 2014 at 10:18 Comment(2)
The only thing you can't do is provide the body alongside the in-class declaration. (i.e. after the = 0 part) Syntax stuff.Rosemare
@Corotto I know, I was after "call one without a body." Answer amendedEthnomusicology
E
2

A pure virutal function can have an implementation. Best example: a pure virtual destructor must have an implementation because all destructors will be called when an an object is destroyed.

Entity answered 6/2, 2014 at 10:44 Comment(0)
E
0

Taking out the linker error from @Angew's answer. Not sure about the undefined behavior happening here...

struct Base
{
    virtual void method() = 0;
};

void Base::method(){}

struct Derived : Base
{
    void method() { Base::method(); };
};

int main()
{
  Derived d;
  d.method();
}

Live Demo

Endoplasm answered 6/2, 2014 at 10:24 Comment(1)
Shouldn't this be a comment to Angews answer (like PlasmaHH did?)Fossick

© 2022 - 2024 — McMap. All rights reserved.