Overload pure virtual function with non pure virtual version [duplicate]
Overload pure virtual function with non pure virtual version [duplicate]
This question already has an answer here:
With Base and Derived defined like this:
class Base
public:
virtual int f1(int a) const = 0;
virtual int f2(int a, int b) const return a+b;
;
class Derived : public Base
public:
int f1(int a) const return a;
;
int main()
Derived obj;
cout << obj.f1(1) << endl;
cout << obj.f2(1, 2) << endl;
The result is
1
3
obj.f1(1) uses the f1 implementation from Derived and obj.f2(1, 2) uses the implementation inherited from Base, which is what I want.
Now, I would like these two functions to have the same name, f, so the base class provides an implementation when there are two parameters and the derived class must implement the single parameter version (that's why it's pure virtual).
However, if I do this (just rename f1 and f2 to f):
class Base
public:
virtual int f(int a) const = 0;
virtual int f(int a, int b) const return a + b;
;
class Derived : public Base
public:
int f(int a) const return a;
;
int main()
Derived obj;
cout << obj.f(1) << endl;
cout << obj.f(1, 2) << endl;
I get the following error:
20:23: error: no matching function for call to 'Derived::f(int, int)'
20:23: note: candidate is:
14:13: note: virtual int Derived::f(int) const
14:13: note: candidate expects 1 argument, 2 provided
Why is this? Is it not possible to do this kind of overloading?
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
5 Answers
5
You need to write
class Derived : public Base
public:
using Base::f;
int f(int a) const return a;
;
Note the using
statement. That brings the base class version back into scope.
using
Now, I would like these two functions to have the same name, f
f
You need to write
class Derived : public Base
public:
using Base::f;
int f(int a) const return a;
;
Note the using
statement. That brings the base class version back into scope. [Thanks to @Bathsheba]
using
Why is this? Is it not possible to do this kind of overloading?
No, not possible as written in the original question due to [basic.scope.hiding¶3]:
In a member function definition, the declaration of a name at block
scope hides the declaration of a member of the class with the same
name; see [basic.scope.class]. The declaration of a member in a
derived class hides the declaration of a member of a base class of the
same name; see [class.member.lookup].
This clause is about names, not overloads. As such, it doesn't matter if there are other overloads in the base class, they all share the same name, which is hidden according to quote above.
Do please feel free to copy my answer into the top of this one; it would read much better with it.
– Bathsheba
Sep 17 '18 at 10:24
Reads very nicely now - have an upvote!
– Bathsheba
Sep 17 '18 at 10:34
@Bathsheba Shall we also downvote your answer to be even more supportive? :)
– lubgr
Sep 17 '18 at 10:37
Ha. @lubgr: Feel free - it's not as good as this answer.
– Bathsheba
Sep 17 '18 at 10:38
@Bathsheba "This answer is not useful" certainly doesn't apply to your fixed-OP's-issue-in-10-seconds post.
– lubgr
Sep 17 '18 at 10:44
You can either pull all definitions of Base into scope with by writing using Base::f;
or you can explcitily write for some versions of f something like this: int f(int a, int b) const override return Base::f(a,b);
using Base::f;
int f(int a, int b) const override return Base::f(a,b);
class Derived : public Base
public:
int f(int a) const return a;
int f(int a, int b) const override return Base::f(a,b);
;
The version with using is already mentioned in this answer:
class Derived : public Base
public:
using Base::f;
int f(int a) const return a;
;
Note: I know that the second version does not work on MSVC 2010. I am also aware this compiler is ancient, but just for people who care ;)
In addition to the other solutions, if you don't want to redefine f
you could explicitly invoke f
of the base class using
f
f
int main()
Derived obj;
cout << obj.f1(1) << endl;
cout << obj.Base::f2(1, 2) << endl;
You can also make them all pure and then override them in the derived class. And you can continue to use your class as you want.
The problem with this answer is that you're inflicting extra work on the descendent to actually implement f2(). The original f2() is not pure virtual presumably because the base implementation is sufficient for many (most?) of their use-cases, but wanted to leave it open for descendants to override it should it become necessary.
– Andre Kostur
Sep 17 '18 at 14:00
@AndreKostur, your are completely right on this point.
– Ibrahima Keita
Sep 17 '18 at 17:29
@StoryTeller It is, indeed. When I did the research I thought it had something to do with one of the functions being pure virtual, so I guess that's why I didn't find that question. This answer: stackoverflow.com/a/1629074/1755482 gives a nice explanation of the name hiding phenomenon.
– Milo
Sep 17 '18 at 10:58