1

I have three different implementations of an interface (solving systems of equations). The old interface essentially was void foo(int *f) within a class. Now I want to generalize this to a case where I solve N systems at the same time. For this I want to have the interface void foo(int *f[N]).

In the codebase there is an abstract class defining the interface, then three classes derive from that class. I would like to add my generalization without breaking existing code. Therefore I thought of adding the new interface and have the old interface delegate to the new one. This is my compressed version:

#include <iostream>

struct AbstractClass {
    /// Old interface, needs to be retained.
    virtual void foo(int *f) {
        std::cout << "AbstractClass::foo(int *f)\n";
        int *a[2] = {f, nullptr};
        foo(a);
    }

    /// New interface.
    virtual void foo(int *f[2]) {
        std::cout << "AbstractClass::foo(int *f[2])\n";
    }
};

struct Derived : public AbstractClass {
    /// New interface.
    void foo(int *f[2]) override {
        std::cout << "Derived::foo(int *f[2])\n";
    }
};

int main(int argc, char **argv) {
    // Code using the old interface.
    Derived d;
    int *a;
    d.foo(a);
}

Work with the code.

My hope is that the call of d.foo(a) would go to the inherited Derived::foo(int *f) and from there to Derived::foo(int *f[2]). However, g++ 6.3 gives me the following (in C++11 mode):

inheritance-test.cpp: In function 'int main(int, char**)':
inheritance-test.cpp:31:12: error: no matching function for call to 'Derived::foo(int*&)'
     d.foo(a);
            ^
inheritance-test.cpp:21:10: note: candidate: virtual void Derived::foo(int**)
     void foo(int *f[2]) override {
          ^~~
inheritance-test.cpp:21:10: note:   no known conversion for argument 1 from 'int*' to 'int**'

It looks like the derived objects do not really have inherited the methods that I want.

Using runtime polymorphism with a pointer to the base class does work, though:

AbstractClass *pd = new Derived();
int *a = nullptr;
pd->foo(a);
delete pd;

I do not really understand why it does not work without the pointer. The vtable is not used with automatic storage because the function calls are bound at compile time (early binding)?

This is getting me a bit closer to the solution, but I would still have to touch all the code which uses this library. However, that is not really an option, the old stuff has to keep working.

What can I do about that (other than duplicating all code)? Would it be sufficient to have this delegation copied into each derived class?

Martin Ueding
  • 8,245
  • 6
  • 46
  • 92
  • Virtual functions only behave polymorphically when called via a pointer or a reference. That's how the language is specified. –  Mar 03 '17 at 21:13
  • Can you accumulate that into a [MCVE] at coliru.stacked-crooked.com or such letting us experimenting with you code please? – πάντα ῥεῖ Mar 03 '17 at 21:14
  • @πάνταῥεῖ: I have added a link to the website you mentioned. Is that what you meant? – Martin Ueding Mar 03 '17 at 21:20

1 Answers1

2

There is something known as name hiding in C++. Basically, when you override a member function in a derived class, it hides all other overloads found in the base class.

That is why below fails:

Derived d;
int *a;
d.foo(a);

And below works:

AbstractClass *pd = new Derived();
int *a = nullptr;
pd->foo(a);

Because the overload of foo that takes a pointer is in AbstractClass but is hidden in Derived.


You can make those overloads visible with a using.

struct Derived : public AbstractClass {

    using AbstractClass::foo;
    void foo(int *f[2]) override {
        std::cout << "Derived::foo(int *f[2])\n";
    }
};

Demo

Community
  • 1
  • 1
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68