Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Legally invoking a pure virtual function

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 :-)

like image 764
Tristan Brindle Avatar asked Feb 06 '14 10:02

Tristan Brindle


2 Answers

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.

like image 52
Mike Seymour Avatar answered Nov 01 '22 02:11

Mike Seymour


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.

like image 2
Angew is no longer proud of SO Avatar answered Nov 01 '22 03:11

Angew is no longer proud of SO