user997112
user997112

Reputation: 30615

Statically-enforcing a C++ class interface without using virtual methods

I have a parent and child class:

class Parent
{
    virtual void mustDefine() = 0;
};

class Child : public Parent
{
    virtual void mustDefine(){}
};

I want to force all child classes of Parent to implement mustDefine(). However, my object type is known at compile-time and I therefore don't want a polymorphic v-table lookup.

Is there a static way to force child classes to implement parent methods?

Upvotes: 0

Views: 494

Answers (3)

Caleth
Caleth

Reputation: 62636

You don't need a class Parent here. What you have is a Named Requirement

class Child1
{
    void mustDefine() { ... }
};

class Child2
{
    void mustDefine() { ... }
};

class NotChild
{
};

template<typename T>
void usesMustDefine(T t)
{
    t.mustDefine();
}

int main()
{
    Child1 c1;
    Child2 c2;
    NotChild c3;

    usesMustDefine(c1); // Succeeds
    usesMustDefine(c2); // Succeeds
    // usesMustDefine(c3); // Fails

    c1.mustDefine(); // Succeeds
    c2.mustDefine(); // Succeeds
    // c3.mustDefine(); // Fails

    return 0;
}

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385104

If you need to enforce your programmers to hide a base class member function by implementing a function of the same name in the derived class.... then leave the base class member function undefined. Attempts to call it will result in linker errors and build failure.

If your users don't try to call the function then the build will still work, which is not necessarily true of virtual functions. But do you care about that?

struct Parent
{
    void mustDefine();
};

struct Child : Parent
{
    // Link failure if this is missing, due to call in main().
    // That's because, without Child::mustDefine() hiding
    // Parent::mustDefine(), lookup for `mustDefine` will find
    // Parent::mustDefine() instead... which is, well, undefined.
    void mustDefine() {}
};

int main()
{
    Child c;
    c.mustDefine();
}

Upvotes: 4

UKMonkey
UKMonkey

Reputation: 6983

The most obvious way, although having worked with code like this I strongly recommend you don't do it, is to use templates:

template<Impl>
void thing(Impl thingy) {
    thingy.mustDefine();
}

The result will be that Impl must have the function "mustDefine", else you'll get compile errors, but it's truely a maintenance nightmare. People won't know what Impl really is, and when they decide they want to write a new one, they can't work out the full list of things that they need to implement.

I would suggest though that this is an XY question, and that the reason for you not wanting to call virtual methods be addressed.

Upvotes: 1

Related Questions