2

I have a derived class where I want one of the functions to override its version in the base class, but have a different signature. Simple example:

#include "stdio.h"

bool use_foo = false;

class Foo {
public:
    virtual int func(double x) { printf ("%f in Foo!\n", x); }
};

class Bar : public Foo {
public:
    int func(short x) { printf ("%d in Bar!\n", x); }
};

int main () {
    Foo* A;
    if (use_foo) 
        A = new Foo;
    else 
        A = new Bar;

    A->func(2);
    return 0;
}

The above code would call the base class copy even though A was allocated as the derived class:

> g++ test.cpp -o test -O3 && ./test
2.000000 in Foo!

Because (as far as my understanding goes) the argument can be converted to match the base class signature, and the derived class doesn't override it because of this difference (but wouldn't it hide it in that case?). If I change the base class function to have short as argument as well, the derived class does manage to override it.

Is there a simple way to convince the call to use the correct function based on the pointer? I could add another function like this:

class Bar : public Foo {
public:
    int func2(short x) { printf ("%d in Bar!\n", x); }
    int func(double x) { func2(x); }
};

But then I would convert the arguments all the time (short->double->short), and this function is performance critical. Is there a better way?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Leeor
  • 19,260
  • 5
  • 56
  • 87
  • 1
    "... I want one of the functions to override its version in the base class, but have a different signature ..." - sorry, that's just not how virtual functions work. – Jesper Juhl Mar 24 '18 at 13:33
  • 8
    Different signatures means different functions. Why is it a shock? – StoryTeller - Unslander Monica Mar 24 '18 at 13:33
  • 1
    Instead of having a different signature, give it a different name. A different signature is equivalent to a different name, but in addition also shadows the function name in the base class. – Eljay Mar 24 '18 at 13:38

2 Answers2

4

These function signatures are not identical:

virtual int func(double x) {...} // base class
int func(short x) {...} // derived class

One uses double parameter, the other uses short. For overriding to occur several conditions must be met. Identical parameter types of the base and derived functions being one of them. Bellow is the excerpt from the "Modern Effective C++" book by Scott Meyers on all the requirements:

• The base class function must be virtual.

• The base and derived function names must be identical (except in the case of destructors).

• The parameter types of the base and derived functions must be identical.

• The constness of the base and derived functions must be identical.

• The return types and exception specifications of the base and derived functions must be compatible.

Alternatively, make the signatures the same and perform the casting inside a derived function body:

int func(double x) override {
    short temp = static_cast<short>(x);
    // ...
}
Ron
  • 14,674
  • 4
  • 34
  • 47
  • Right, I wanted something that would allow me to override one with the other such that the argument would only be casted when necessary. Anyway, it's probably bad design... – Leeor Mar 24 '18 at 14:24
1

What sense does this make anyway? The reason you use a virtual function is that the caller should only be required to know the base class, and thus only the base-class signature.

In other words, code which has, say, a Foo& or a Foo* or a std::unique_ptr<Foo>, only knows about the double version of your function anyway. It will pass a double when it calls func, because what else should it do?

Perhaps what you really want to do is the subclass implementation of the function to convert the double to a short. Here's an example for that, which also gets rid of the printf in favour of a type-safe C++ stream:

class Bar : public Foo {
public:
    int func(double x) { std::cout << static_cast<short>(x) << " in Bar!\n"; }
};

Note that since C++11, you are encouraged to use override to mark overriding functions.

and this function is performance critical.

  1. Should a performance-critical function be virtual at all?
  2. Have you actually measured the speed? Is there a noticeable delay? Or are computers too fast anyway?
Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • You were right to question the sense in that. Turns out the type of the argument is also dictated by the class, so instead of providing short/double, I can just provide the means to extract that argument from the class (some index to an internal storage), and that has the same signature. – Leeor Mar 24 '18 at 14:27