How to implement `final` semantics pre C++11?

C++11 introduced the final specifier, which allows a base class to prevent derivation or overriding of virtual functions in derived classes.

How can I enforce similar constraints on class inheritance and function overriding pre C++11?

  • 2

    The paper proposing the idea open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1827.htm . Note it does not propose the final syntax but does outline the motivation. See the links from en.cppreference.com/w/cpp/11 (search for “final”) for the final syntax

    – 




  • 2

    Why? Code that works correctly with final will also work correctly without it. final is one of many nanny techniques that allow designers to tell users that they have to do things in a particular way, because, after all, I’m the designer and you’re just a user, and nobody could think of a way of using my classes that’s different from what I had in mind.

    – 

  • @PeteBecker an interesting discussion but off-topic for this question, which is about “how” rather than “why”

    – 

  • 1

    Not only is C++11 a well-established standard, but so is C++14, C++17 and C++20. Asking about C++98 really should go to RetroComputing.SE by now, it’s a quarter century ago.

    – 

Best I can suggest is making the constructor private and enforcing a factory function for instantiation:

class Foo
{
public:
    static Foo* makeInstance(int initialX)
    {
        return new Foo(initialX);
    }


private:
    Foo(int initialX) :x(initialX) {}
    int x;
    int setX(int value) { x = value; }
    int getX() { return x; }
};

That should prevent inheritance. But it does require your callers to explicitly instantiate the object via the static makeInstance function or similar. And then explicitly delete it.

You can also have it return the object copy instead of by pointer.

static Foo makeInstance(int initialX)
{
    return Foo(initialX);
}

Making the class behave somewhat like “final” can be achieved using virtual inheritance and class friendship.

Personally I would not recommend using it in this manner, but it’s certainly possible.

class seal
{
    friend class impl1;
    friend class impl2;
    seal() {} // note it's private!
};

struct interface
{
    virtual ~interface() {}
};

struct impl1 : interface, virtual seal
{};

struct impl2 : interface, virtual seal
{};


struct impl3 : impl2{}; // declaration works...

int main()
{
    impl1 i1;
    impl2 i2;
    impl3 i3; // ...but fails to compile here
}

https://godbolt.org/z/MjKhbaTo8

Leave a Comment