问题
I'm struggling a bit to understand why this code snippet does not compile.
#include <cstdio>
class A {
public:
virtual int potential()=0;
virtual int potential(int arg, int arg2)=0;
};
class B : public A {
public:
int potential() { return 1; }
virtual int potential(int arg, int arg2) { return 2; }
};
class C : public B {
public:
int potential(int arg, int arg2) { return 3; }
};
int main(int argc, char** argv) {
C c;
int value = c.potential();
printf("Got %i\n", value);
return 0;
}
I have two pure virtual methods, both named potential in the abstract superclass A. The subclass B then defines both, but a further subclass C only needs to redefine one of the methods.
However, on compilation, only the method defined in C is recognized, and potential() isn't seen (this should have been inherited from B):
In function 'int main(int, char**)':
Line 23: error: no matching function for call to 'C::potential()'
compilation terminated due to -Wfatal-errors.
If I rename A::potential(int, int) to something else all the way down the inheritance tree, such as A::somethingElse(int, int), then the code compiles fine, and the output is Got 1, as expected.
This has been verified using clang, g++ and MSVC's cl.
Any ideas on what is going on?
回答1:
However, on compilation, only the method defined in C is recognized, and potential() isn't seen (this should have been inherited from B).
C++ doesn’t work like this: because you implemented a different potential method (a method of the same name but with different parameters) in C, the other method is hidden as far as C is concerned.
Hiding happens because of the way that C++ resolves (overloaded) method names: when you call a method potential on an instance of a class (here c), C++ searches in the class whether a method of that name exists. If that isn’t the case it continues its search in the base classes. It goes further up in the hierarchy until at least one method of that name is found.
But in your case, C++ doesn’t have to search far: the method already exists in C, so it stops its search. Now C++ tries to match the method signature. Unfortunately, the method signature doesn’t match but at this time it’s too late: overload resolution fails; C++ doesn’t search for other methods that might match.
There are three solutions:
Import it with
usingin C:class C : public B { public: using B::potential; int potential(int arg, int arg2) { return 3; } };Call the method from a base class instance in
main:C c; B& b = c; int value = b.potential();Qualify the name explicitly in
main:C c; int value = c.B::potential();
回答2:
The problem is name hiding.
Function overloads and function inheritance aren't best friends. Usually you either [hmm, what's "either" for three?]:
- Overload a function within a single class. Everything works fine.
- Inherit a non-overloaded function from a base class. Everything works fine.
- Re-implement a non-overloaded function from a base class
Bin a derived classC.C::funchidesB::funcbecause it has the same name.
You're using inheritance and overloading, and your C::func is hiding B::func and every overload of it, even the ones that aren't re-implemented in C.
It's a bit of a quirky confusion of C++, but it's easily resolved.
In short, the solution is to bring B::potential() into scope for C with the using statement:
class C : public B {
public:
using B::potential; // brings overloads from B into scope
int potential(int arg, int arg2) { return 3; }
};
I have written an article here that demonstrates the issue in depth.
来源:https://stackoverflow.com/questions/5896908/understanding-simple-c-inheritance