2

Let's assume I have a hierarchy of several classes each derived from each other using virtual functions. The base class acts as an interface and defines functions, which may not be required by all of the derived classes. Now I wonder what the best practice is for such intermediate functions. Should those still be implemented and simple chain down to the base class, or should they be skipped? The problem I have is, that implementing such a function, when it isn't needed, simply adds noise to the code. On the other hand, when using a higher class, in C++ you can not simply call a superclass method (like in Java), so you need to know in which base class the method is really implemented. And to my mind, this would violate encapsulation, because I would need to know some implementation details of the base class.

To illustrate what I mean here is an artifical exmaple:

class MyInterface
{
    virtual void foo(bool) = 0;
    virtual void foo1(int) = 0;
};

class Base : public MyInterface
{
    void foo(bool param) override
    {
        // do some stuff here.
    }

    void foo1(int param) override
    {
        // do some stuff here.
    }
};


class A : Base
{
    void foo(bool param) override
    {
        // do some stuff here.
        Base::foo(param);
    }
    // class doesn't need foo1() here so it is not implemented.
};


class B : A
{
    void foo(bool param) override
    {
        // do some stuff here.
        A::foo(param);
    }

    void foo1(int param) override
    {
        // This class needs foo1() but as A doesn't have it implemented
        // I have to knwo this and skip A going directly to Base
        Base::foo1(1);
    }
};

Here the class B needs to know that A doesn't implement foo1 and has to skip it. Of course this can be seen in the header, but if I want to later change class A it shouldn't be neccessary to touch all the other classes that are derived from it (encapsulation and isolation principle) So even worse, if I implement now foo1() in A later, B would still skip it and never realise that the functionality has changed.

So from an object model point of view I would assume that such empty functions should still be designed into a class?

2
  • 2
    or use a language that has a super construct that takes the next available implementation Aug 29, 2014 at 7:49
  • 2
    You can insert an using Base::foo1; in class A, after which A::foo1(1); will work.
    – Sjoerd
    Aug 29, 2014 at 15:19

2 Answers 2

1

You're right, this is a flaw in the language itself which means that despite all the advantages which come from inheritance, you still have to know how it is implemented. It would be ideal to be able to call super within the method and have it call the appropriate method, whatever that might be. This is one of the things that Java tried to improve upon.

As you said, you could get around it by implementing every method in class A, and so in doing so, you prevent complications later on. It is a bit of a pain, but I suppose it is a necessary evil for creating a proper library to be used by others. Note that only the class being made available in the library for use has to implement all virtual methods, and not any internally used classes unless you require otherwise.

While not a solution, a slightly friendlier approach (albeit a little hacky) might be to typedef "super" as a private type definition for the base class. As in the case of class B, you'd have:

private:  
    typedef A super;

Likewise in class A, you could define:

private:
    typedef Base super;

At least if you're the one writing the code, rather than have to know the name of the class, you could do:

class B : A
{
    void foo(bool param) override
    {
        // do some stuff here.
        super::foo(param);
    }

    void foo1(int param) override
    {
        super::super::foo1(1);
    }
};

Again, while this doesn't fix your problem, it makes it slightly more manageable.

See here for more details.

1
  • I think for a straightforward hierarchy this could be indeed a good approach, even though you can't enforce other users to adopt it. I guess for multiple inherited objects this will not work though. At least this looks like the best one can do.
    – Devolus
    Aug 29, 2014 at 9:47
2

Just call the immediate base class version of the function. If that function is not implemented in that immediate base class the compiler calls the one in the parent of that base and so on until it finds an ancestor that actually implements the function.

1
  • I'm looking for exactly this answer but I want to find something in the standard about that behavior of the compiler. Is this guaranteed? Do you know what to search for to find similar discussions about skipped inheritance hierarchy methods? Apr 5, 2018 at 11:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.