Understanding (simple?) C++ Inheritance

半世苍凉 提交于 2019-12-31 19:28:14

问题


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:

  1. Import it with using in C:

    class C : public B {
    public:
        using B::potential;
        int potential(int arg, int arg2) { return 3; }
    };
    
  2. Call the method from a base class instance in main:

    C c;
    B& b = c;
    int value = b.potential();
    
  3. 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 B in a derived class C. C::func hides B::func because 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!