Search code examples
c++finalobject-slicing

C++ final class and slicing idiom


I happened to be browsing the source for mongoDB, and found this interesting construct:

class NonspecificAssertionException final : public AssertionException {
public:
    using AssertionException::AssertionException;

private:
    void defineOnlyInFinalSubclassToPreventSlicing() final {}
};

How does the private method prevent slicing? I can't seem to think of the problem case.

Cheers, George


Solution

  • The only member functions to which the final specifier may be applied are virtual member functions. It is likely that in AssertionException or one of it's own base classes, this member is defined as

    virtual void defineOnlyInFinalSubclassToPreventSlicing() = 0;
    

    Thus, all classes in the hierarchy save the most derived ones are abstract base classes. One may not create values of abstract classes (they can only serve as bases). And so, one may not accidentally write

    try {
        foo();
    }
    catch(AssertionException const e) { // oops catching by value
    } 
    

    If AssertionException was not abstract, the above could be written. But when it's abstract the compiler will complain at that exception handler, forcing us to catch by reference. And catching by reference is recommended practice.

    Marking the member (and class) as final ensures no further derivation is possible. So the problem cannot reappear accidentally when the inheritance hierarchy is changed. Because a programmer that adds another class and again defines defineOnlyInFinalSubclassToPreventSlicing as final will elicit an error from the compiler, on account of this member already being declared final in the base. They will therefore have to remove the implementation from the base class, thus making it abstract again.

    It's a bookkeeping system.