c++virtual-functionstemplate-classespure-function

Member method calls virtual method with same name but different signature


I have the following Header/Source files:

// foo.h
#ifndef __FOO_H
#define __FOO_H

#include <map>
#include <stdexcept>

template <typename T>
class FooBase {

public:
    std::map<float,T> a;
    FooBase(std::map<float,T> a_) : a(a_) {};
    T func(float x1, T fallback) const;
    virtual T func(float x1) const = 0;
};

class Foo: public FooBase<float> {
public:
    Foo() : FooBase<float>({}) {};
    float func(float x1) const;
    // float func(float x1, float fallback) const;
};
void test_foo1();
void test_foo2();

#endif // __FOO_H
// foo.cpp
#include "foo.h"

template <typename T>
T FooBase<T>::func(float x1, T fallback) const {
    try {
        return (func(x1));
    } catch(std::runtime_error&) {
        return fallback;
    }
};

float Foo::func(float x1) const {
    return 2.0;
};

template class FooBase<float>;

void test_foo1() {
    Foo foo;
    float b = foo.func(1.0, 2.0);
}
void test_foo2() {
    Foo foo;
    float b = foo.func(1.0);
}

It is crucial, that the "fallback"-Version of func has the same name as a virtual function but different signature, whereas the single-signature version of func will be specified in the child class Foo.

The test_foo1-Function won't compile:

[  3%] Building CXX object foo.cpp.o
foo.cpp: In function ‘void test_foo1()’:
foo.cpp:20:29: error: no matching function for call to ‘Foo::func(double, double)’
   20 |  float b = foo.func(1.0, 2.0);
      |                             ^
foo.cpp:12:7: note: candidate: ‘virtual float Foo::func(float) const’
   12 | float Foo::func(float x1) const {
      |       ^~~
foo.cpp:12:7: note:   candidate expects 1 argument, 2 provided

If I activate the commented declaration line in foo.h, it compiles, but won't be able to resolve when test_foo1 is called in another source file. In this case I used a catch2-Test which fails when test_foo1 is included, while test_foo2 makes no problems:

[ 98%] Linking CXX executable ...
/usr/bin/ld: libFoo.so: undefined reference to `Foo::func(float, float) const'

Can anyone tell me if I'm totally wrong in how to achieve this? I hesitate to share the full logic of the build, because possibly the repeated declaration might be wrong approach anyways. I hope that fact that test_foo2 works in the other source file generates enough trust to rule out problems located outside of the shared code.

The basic idea is in the GOF-language a "template-method pattern" with a hook-function that has no default. Special is that the hook-method has the same name as the function calling it. The fact that the class has state (a) and a template parameter might make an effect, at least I think that I achieved something like this in simpler situations, therefore I included the state and the template parameter in the "minimal example", hope that does not make things too complicated.

Thanks for any help.


Solution

  • Foo::func hides FooBase::func. You can use using to pull FooBase::func into Foos scope:

    class Foo: public FooBase<float> {
    public:
        Foo() : FooBase<float>({}) {};
        float func(float x1) const;
        using FooBase<float>::func;
    };
    

    Live Demo

    Alternatively you can explicitly pick FooBase::func to be called:

    void test_foo1() {
        Foo foo;
        float b = foo.FooBase<float>::func(1.0, 2.0);
    }