Ajay
Ajay

Reputation: 18431

Allow a mock class to inherit from a final class

We may declare a final/sealed non-inheritable class using the new C++ keyword final.

class Generator final
{

};

This class may inherit from other, may or may not have virtual (inherited or not). But, how to make it final, yet allow one class to inherit from it?

We mostly need to derive a mock class from real class (with or without late-binding, hence virtual isn't important). How to make it work:

class MockGenerator : Generator{};

But disallow any other inheritance?

Upvotes: 4

Views: 4572

Answers (3)

Sam
Sam

Reputation: 180

If you need to create mock class it for unit-testing, then you can try Typemock Isolator++. Because it easily handles with final classes. You don't even need to change something in you production code (like creation of separate mock class). I've created simple test to demonstrate it:

class Generator final
    {
        public:
            int foo()
            {
                return 0;
            }
    };

    TEST_METHOD(TestFinal)
    {
        Generator* generator = FAKE<Generator>();
        WHEN_CALLED(generator->foo()).Return(1);

        int result = generator->foo();

        Assert::AreEqual(1, result);
    }

Hope it can be useful for you.

Upvotes: 1

stefaanv
stefaanv

Reputation: 14392

One possibility: use a define for final and define it as empty when generating the test environment.

#ifdef MOCK
#define CLASS_FINAL
#else
#define CLASS_FINAL final
#endif

edit: I agree with the comment of utnapistim: this is not a recommendation, just a technical possibility (but at least better than #define final).

Upvotes: 5

utnapistim
utnapistim

Reputation: 27385

But, how to make it final, yet allow one class to inherit from it?

That's not possible.

We mostly need to derive a mock class from real class (with or without late-binding, hence virtual isn't important).

If the class is final, you do not need to derive from it. If you do need to derive from it, it is not final. Pick one.

Edit: You can add restrictions to your class, but those come at their own cost to the interface:

class Generator // not final
{
    Generator(); // the only accessible constructor is private

    // whitelist who has access to this constructor
    friend class MockGenerator;
public:
    // no public constructors here except for copy & move

    Generator(Generator&);
    Generator(Generator&&);
    ...

    // provide controlled access to the private constructor
    static Generator make_generator() { return Generator(); }

    // rest of API here
};

This is a class that allows it's factory and MockGenerator specializations to call it's constructor. This comes at the price of blocking trivial construction though.

Old code (no longer compilable):

Generator instance;

New code (enforced by the private constructor):

auto instance = Generator::make_generator();

Upvotes: 6

Related Questions